Skip to content

Commit 61cbfa3

Browse files
authored
Merge pull request #22 from johnsyweb/paj/2021
Version One
2 parents 1bc3c1d + bb37224 commit 61cbfa3

File tree

12 files changed

+299
-238
lines changed

12 files changed

+299
-238
lines changed

.flake8

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[flake8]
2+
exclude = docs/
3+
max-line-length = 120

.github/workflows/python-upload.yml

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
---
2+
name: Upload Python Package
3+
4+
on:
5+
release:
6+
types: [created]
7+
8+
jobs:
9+
deploy:
10+
runs-on: ubuntu-latest
11+
steps:
12+
- name: Checkout
13+
uses: actions/checkout@v2
14+
15+
- name: Set up Python
16+
uses: actions/setup-python@v2
17+
with:
18+
python-version: '3.x'
19+
20+
- name: Install dependencies
21+
run: |
22+
python -m pip install --upgrade pip
23+
pip install setuptools wheel twine
24+
25+
- name: Build and publish
26+
env:
27+
TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }}
28+
TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
29+
run: |
30+
python setup.py sdist bdist_wheel
31+
twine upload dist/*

.github/workflows/python.yml

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# This workflow will install Python dependencies, run tests and lint with a variety of Python versions
2+
# For more information see:
3+
# https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
4+
5+
name: Python
6+
7+
on: [push, pull_request]
8+
9+
jobs:
10+
build:
11+
12+
runs-on: ubuntu-latest
13+
strategy:
14+
matrix:
15+
python-version: [3.6, 3.7, 3.8, 3.9]
16+
17+
steps:
18+
- name: Checkout
19+
uses: actions/checkout@v2
20+
21+
- name: Set up Python ${{ matrix.python-version }}
22+
uses: actions/setup-python@v2
23+
with:
24+
python-version: ${{ matrix.python-version }}
25+
26+
- name: Install dependencies
27+
run: |
28+
python -m pip install --upgrade pip
29+
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
30+
31+
- name: Lint with flake8
32+
run: flake8
33+
34+
- name: Test with pytest
35+
run: pytest --cov=sparse_list --cov-report=xml --cov-report=html --junitxml=test-results-${{ matrix.python-version }}.xml
36+
37+
- name: Upload pytest test results
38+
uses: actions/upload-artifact@v2
39+
with:
40+
name: pytest-results-${{ matrix.python-version }}
41+
path: |
42+
coverage.xml
43+
htmlcov/
44+
test-results-${{ matrix.python-version }}.xml
45+
if: ${{ always() }}
46+

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,9 @@
22
/.coverage
33
/MANIFEST
44
/build/
5+
/coverage.xml
56
/dist/
67
/docs/_build
8+
/htmlcov/
9+
/sparse_list.egg-info/
10+
/test-results-*.xml

.tool-versions

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
python 3.9.0

.travis.yml

Lines changed: 0 additions & 11 deletions
This file was deleted.

README.rst

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,8 @@ Inspired by the post `Populating a sparse list with random
55
1's <http://stackoverflow.com/q/17522753/78845>`__ on
66
`StackOverflow <http://stackoverflow.com/>`__.
77

8-
A "sparse list" is a list where most (say, more than 95% of) values will
9-
be None (or some other default) and for reasons of memory efficiency you
10-
don't wish to store these (cf. `Sparse
8+
A "sparse list" is a list where most values will be None (or some other default)
9+
and for reasons of memory efficiency you don't wish to store these (cf. `Sparse
1110
array <http://en.wikipedia.org/wiki/Sparse_array>`__).
1211

1312
This implementation has a similar interface to Python's built-in list
@@ -29,7 +28,7 @@ Usage
2928
-----
3029

3130
See the
32-
`unit-tests <https://github.com/johnsyweb/python_sparse_list/blob/master/test_sparse_list.py>`__!
31+
`unit-tests <https://github.com/johnsyweb/python_sparse_list/blob/HEAD/test_sparse_list.py>`__!
3332

3433
Contributing
3534
------------
@@ -38,7 +37,7 @@ Contributing
3837
2. Create your feature branch (``git checkout -b my-new-feature``)
3938
3. Commit your changes (``git commit -am 'Add some feature'``)
4039
4. Ensure the tests pass for all Pythons in
41-
`.travis.yml <https://github.com/johnsyweb/python_sparse_list/blob/master/.travis.yml>`__
40+
`.python.yml <https://github.com/johnsyweb/python_sparse_list/blob/HEAD/.github/workflows/python.yml>`__
4241
5. Push to the branch (``git push origin my-new-feature``)
4342
6. Create new Pull Request
4443

@@ -62,5 +61,5 @@ contributors, you can find their details here:
6261

6362
https://github.com/johnsyweb/python_sparse_list/graphs/contributors
6463

65-
.. |Build Status| image:: https://travis-ci.org/johnsyweb/python_sparse_list.png
66-
:target: https://travis-ci.org/johnsyweb/python_sparse_list
64+
.. |Build Status| image:: https://github.com/johnsyweb/python_sparse_list/actions/workflows/python.yml/badge.svg
65+
:target: https://github.com/johnsyweb/python_sparse_list/actions/workflows/python.yml

requirements.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
coverage
2-
nose
3-
six
1+
flake8
2+
pytest
3+
pytest-cov

setup.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from setuptools import setup
22
import os
33

4-
version = '0.9'
4+
version = '1.0'
55
github_url = 'https://github.com/johnsyweb/python_sparse_list'
66
paj = 'Pete Johns'
77
paj_email = 'paj+pypi@johnsy.com'
@@ -10,7 +10,7 @@
1010
name='sparse_list',
1111
py_modules=['sparse_list'],
1212
version=version,
13-
description='A list where most (>95%) values will be None (or default)',
13+
description='A list where most values will be None (or some other default)',
1414
author=paj,
1515
author_email=paj_email,
1616
maintainer=paj,
@@ -24,10 +24,11 @@
2424
"License :: OSI Approved :: MIT License",
2525
"Operating System :: OS Independent",
2626
"Programming Language :: Python",
27-
"Programming Language :: Python :: 2",
28-
"Programming Language :: Python :: 2.7",
2927
"Programming Language :: Python :: 3",
30-
"Programming Language :: Python :: 3.3",
28+
"Programming Language :: Python :: 3.6",
29+
"Programming Language :: Python :: 3.7",
30+
"Programming Language :: Python :: 3.8",
31+
"Programming Language :: Python :: 3.9",
3132
"Programming Language :: Python :: Implementation :: CPython",
3233
"Programming Language :: Python :: Implementation :: PyPy",
3334
"Topic :: Software Development",
@@ -38,6 +39,5 @@
3839
long_description=(''.join(
3940
[open(f).read() for f in ('README.rst',) if os.path.isfile(f)]
4041
)),
41-
install_requires=['six'],
4242
license='MIT'
4343
)

sparse_list.py

Lines changed: 13 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,13 @@
55
66
http://stackoverflow.com/q/17522753/78845
77
8-
A "sparse list" is a list where most (say, more than 95% of) values will be
9-
None (or some other default) and for reasons of memory efficiency you don't
10-
wish to store these. cf. Sparse array:
8+
A "sparse list" is a list where most values will be None (or some other
9+
default) and for reasons of memory efficiency you don't wish to store these.
10+
cf. Sparse array:
1111
1212
http://en.wikipedia.org/wiki/Sparse_array
1313
'''
1414

15-
try:
16-
xrange
17-
except NameError:
18-
# On Python 3, range() is equivalent to Python 2's xrange()
19-
xrange = range
20-
21-
from six import iteritems, itervalues
22-
2315

2416
class SparseList(object):
2517
'''
@@ -49,7 +41,7 @@ def __setitem__(self, index, value):
4941
if index.start:
5042
self.size = max(self.size, index.start + len(value))
5143
s = slice(index.start, index.stop, index.step).indices(self.size)
52-
for v, i in enumerate(xrange(*s)):
44+
for v, i in enumerate(range(*s)):
5345
self.__setitem__(i, value[v])
5446
except AttributeError:
5547
if value != self.default:
@@ -59,7 +51,7 @@ def __setitem__(self, index, value):
5951
def __getitem__(self, index):
6052
try:
6153
s = slice(index.start, index.stop, index.step).indices(self.size)
62-
indices = xrange(*s)
54+
indices = range(*s)
6355
sl = SparseList(
6456
{
6557
k: self.elements[i]
@@ -80,7 +72,7 @@ def __setslice__(self, start, stop, vals):
8072

8173
def __delitem__(self, item):
8274
if isinstance(item, slice):
83-
keys_to_remove = xrange(*item.indices(self.size))
75+
keys_to_remove = range(*item.indices(self.size))
8476
elif item < 0:
8577
keys_to_remove = (self.size + item, )
8678
else:
@@ -113,11 +105,11 @@ def __delslice__(self, start, stop):
113105
return self.__delitem__(slice(start, stop))
114106

115107
def __iter__(self):
116-
for index in xrange(self.size):
108+
for index in range(self.size):
117109
yield self[index]
118110

119111
def __contains__(self, index):
120-
return index in itervalues(self.elements)
112+
return index in self.elements.values()
121113

122114
def __repr__(self):
123115
return '[{}]'.format(', '.join([str(e) for e in self]))
@@ -149,13 +141,12 @@ def __convert_and_size(key):
149141
raise ValueError('Invalid key: {}'.format(key))
150142
self.size = max(key + 1, self.size)
151143
return key
152-
self.elements = {__convert_and_size(k): v for k, v in iteritems(arg) if v != self.default}
144+
self.elements = {__convert_and_size(k): v for k, v in arg.items() if v != self.default}
153145

154146
def __initialise_from_iterable(self, arg):
155147
for v in arg:
156148
self.append(v)
157149

158-
159150
def __eq__(self, other):
160151
return len(self) == len(other) and all(a == b for a, b in zip(self, other))
161152

@@ -175,15 +166,15 @@ def __ge__(self, other):
175166

176167
def __mul__(self, multiplier):
177168
result = self[:]
178-
for _ in xrange(multiplier - 1):
169+
for _ in range(multiplier - 1):
179170
result += self[:]
180171
return result
181172

182173
def count(self, value):
183174
'''
184175
return number of occurrences of value
185176
'''
186-
return sum(v == value for v in itervalues(self.elements)) + (
177+
return sum(v == value for v in self.elements.values()) + (
187178
self.size - len(self.elements) if value == self.default else 0
188179
)
189180

@@ -204,7 +195,7 @@ def index(self, value):
204195
if v == value:
205196
return k
206197
raise ValueError('{} not in SparseList'.format(value))
207-
for k, v in iteritems(self.elements):
198+
for k, v in self.elements.items():
208199
if v == value:
209200
return k
210201
raise ValueError('{} not in SparseList'.format(value))
@@ -227,7 +218,7 @@ def remove(self, value):
227218
'''
228219
if value == self.default:
229220
return
230-
for k, v in iteritems(self.elements):
221+
for k, v in self.elements.items():
231222
if v == value:
232223
del self.elements[k]
233224
return

0 commit comments

Comments
 (0)