Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Drop support for legacy Python 2.7 #235

Merged
merged 8 commits into from
Mar 1, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,22 +1,21 @@
sudo: False

language: python

cache: pip

matrix:
include:
- python: 2.7
- python: 3.5
- python: 3.5
env: NUMPY_VERSION="<1.14.0"
- python: 3.6
- python: 3.7
dist: xenial
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wasn't aware that you needed this, thanks!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, see travis-ci/travis-ci#9069 / travis-ci/travis-ci#9815 for details (sudo is no longer needed).


install:
- ./ci/01-install.sh

script:
- py.test
- pytest

after_success:
- codecov
Expand Down
6 changes: 3 additions & 3 deletions benchmarks/benchmark_coo.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import sparse


class ElemwiseSuite(object):
class ElemwiseSuite:
def setup(self):
np.random.seed(0)
self.x = sparse.random((100, 100, 100), density=0.01)
Expand All @@ -21,7 +21,7 @@ def time_index(self):
self.x[5]


class ElemwiseBroadcastingSuite(object):
class ElemwiseBroadcastingSuite:
def setup(self):
np.random.seed(0)
self.x = sparse.random((100, 1, 100), density=0.01)
Expand All @@ -34,7 +34,7 @@ def time_mul(self):
self.x * self.y


class IndexingSuite(object):
class IndexingSuite:
def setup(self):
np.random.seed(0)
self.x = sparse.random((100, 100, 100), density=0.01)
Expand Down
4 changes: 2 additions & 2 deletions ci/environment-2.7.yml → ci/environment-3.7.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
name: py27-sparse-test
name: py37-sparse-test
channels:
- conda-forge
dependencies:
- python=2.7
- python=3.7
- pytest
- numpy
- scipy
Expand Down
15 changes: 6 additions & 9 deletions docs/contributing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -60,17 +60,14 @@ Running/Adding Unit Tests
It is best if all new functionality and/or bug fixes have unit tests added
with each use-case.

Since we support both Python 2.7 and Python 3.5 and newer, it is recommended
to test with at least these two versions before committing your code or opening
a pull request. We use `pytest <https://docs.pytest.org/en/latest/>`_ as our unit
testing framework, with the ``pytest-cov`` extension to check code coverage and
``pytest-flake8`` to check code style. You don't need to configure these extensions
yourself. Once you've configured your environment, you can just ``cd`` to
the root of your repository and run
We use `pytest <https://docs.pytest.org/en/latest/>`_ as our unit testing framework,
with the ``pytest-cov`` extension to check code coverage and ``pytest-flake8`` to
check code style. You don't need to configure these extensions yourself. Once you've
configured your environment, you can just ``cd`` to the root of your repository and run

.. code-block:: bash

py.test
pytest

This automatically checks code style and functionality, and prints code coverage,
even though it doesn't fail on low coverage.
Expand All @@ -80,7 +77,7 @@ Unit tests are automatically run on Travis CI for pull requests.
Coverage
--------

The ``py.test`` script automatically reports coverage, both on the terminal for
The ``pytest`` script automatically reports coverage, both on the terminal for
missing line numbers, and in annotated HTML form in ``htmlcov/index.html``.

Coverage is automatically checked on CodeCov for pull requests.
Expand Down
2 changes: 1 addition & 1 deletion readthedocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ build:
image: latest

python:
version: 3.6
version: 3.7
pip_install: true
extra_requirements:
- docs
6 changes: 3 additions & 3 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,11 @@
'Operating System :: OS Independent',
'License :: OSI Approved :: BSD License',
'Programming Language :: Python',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3 :: Only',
'Intended Audience :: Developers',
'Intended Audience :: Science/Research',
],
Expand All @@ -69,5 +69,5 @@
'Source': 'https://github.com/pydata/sparse/',
'Tracker': 'https://github.com/pydata/sparse/issues',
},
python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4',
python_requires='>=3.5, <4',
)
18 changes: 0 additions & 18 deletions sparse/compatibility.py

This file was deleted.

8 changes: 2 additions & 6 deletions sparse/coo/common.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
from functools import reduce, wraps
import operator
import warnings
try:
from collections.abc import Iterable
except (AttributeError, ImportError):
from collections import Iterable
from collections.abc import Iterable

import numpy as np
import scipy.sparse
import numba

from ..sparse_array import SparseArray
from ..compatibility import range, int
from ..utils import isscalar, normalize_axis, check_zero_fill_value, check_consistent_fill_value


Expand Down Expand Up @@ -438,7 +434,7 @@ def stack(arrays, axis=0):
from .core import COO
check_consistent_fill_value(arrays)

assert len(set(x.shape for x in arrays)) == 1
assert len({x.shape for x in arrays}) == 1
arrays = [x if isinstance(x, COO) else COO(x) for x in arrays]
axis = normalize_axis(axis, arrays[0].ndim + 1)
data = np.concatenate([x.data for x in arrays])
Expand Down
10 changes: 3 additions & 7 deletions sparse/coo/core.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
import copy as _copy
import operator
try:
from collections.abc import Iterable, Iterator, Sized
except (AttributeError, ImportError):
from collections import Iterable, Iterator, Sized
from collections.abc import Iterable, Iterator, Sized
from collections import defaultdict, deque
from functools import reduce
import warnings
Expand All @@ -15,7 +12,6 @@
from .common import dot, matmul
from .indexing import getitem
from .umath import elemwise, broadcast_to
from ..compatibility import int, range
from ..sparse_array import SparseArray
from ..utils import normalize_axis, equivalent, check_zero_fill_value, _zero_of_dtype

Expand Down Expand Up @@ -226,7 +222,7 @@ def __init__(self, coords, data=None, shape=None, has_duplicates=True,
else:
shape = ()

super(COO, self).__init__(shape, fill_value=fill_value)
super().__init__(shape, fill_value=fill_value)
self.coords = self.coords.astype(np.intp)

if self.shape:
Expand Down Expand Up @@ -278,7 +274,7 @@ def copy(self, deep=True):
def _make_shallow_copy_of(self, other):
self.coords = other.coords
self.data = other.data
super(COO, self).__init__(other.shape, fill_value=other.fill_value)
super().__init__(other.shape, fill_value=other.fill_value)

def enable_caching(self):
""" Enable caching of reshape, transpose, and tocsr/csc operations
Expand Down
5 changes: 3 additions & 2 deletions sparse/coo/indexing.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
import numba
import numpy as np

from ..compatibility import range, zip_longest
from itertools import zip_longest

from ..slicing import normalize_index
from ..utils import _zero_of_dtype, equivalent

Expand Down Expand Up @@ -582,7 +583,7 @@ def _join_adjacent_pairs(starts_old, stops_old): # pragma: no cover
return starts, stops


class _AdvIdxInfo(object):
class _AdvIdxInfo:
def __init__(self, idx, pos, length):
self.idx = idx
self.pos = pos
Expand Down
5 changes: 3 additions & 2 deletions sparse/coo/umath.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
import numpy as np
import scipy.sparse

from ..compatibility import range, zip, zip_longest
from itertools import zip_longest

from ..utils import isscalar, equivalent, _zero_of_dtype


Expand Down Expand Up @@ -379,7 +380,7 @@ def broadcast_to(x, shape):
sorted=sorted, fill_value=x.fill_value)


class _Elemwise(object):
class _Elemwise:
def __init__(self, func, *args, **kwargs):
"""
Initialize the element-wise function calculator.
Expand Down
5 changes: 2 additions & 3 deletions sparse/dok.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
from .slicing import normalize_index
from .utils import equivalent
from .sparse_array import SparseArray
from .compatibility import int, range, zip


class DOK(SparseArray):
Expand Down Expand Up @@ -108,7 +107,7 @@ def __init__(self, shape, data=None, dtype=None, fill_value=None):
if not data:
data = dict()

super(DOK, self).__init__(shape, fill_value=fill_value)
super().__init__(shape, fill_value=fill_value)

if isinstance(data, dict):
if not dtype:
Expand All @@ -125,7 +124,7 @@ def __init__(self, shape, data=None, dtype=None, fill_value=None):
def _make_shallow_copy_of(self, other):
self.dtype = other.dtype
self.data = other.data
super(DOK, self).__init__(other.shape, fill_value=other.fill_value)
super().__init__(other.shape, fill_value=other.fill_value)

@classmethod
def from_coo(cls, x):
Expand Down
5 changes: 1 addition & 4 deletions sparse/slicing.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,8 @@
# See license at https://github.com/dask/dask/blob/master/LICENSE.txt

import math
from collections.abc import Iterable
from numbers import Integral, Number
try:
from collections.abc import Iterable
except (AttributeError, ImportError):
from collections import Iterable

import numpy as np

Expand Down
9 changes: 2 additions & 7 deletions sparse/sparse_array.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,15 @@
from __future__ import absolute_import, division, print_function
from abc import ABCMeta, abstractmethod
try:
from collections.abc import Iterable
except (AttributeError, ImportError):
from collections import Iterable
from collections.abc import Iterable
from numbers import Integral
from functools import reduce
import operator

import numpy as np

from .utils import _zero_of_dtype
from .compatibility import int


class SparseArray(object):
class SparseArray:
"""
An abstract base class for all the sparse array classes.

Expand Down
7 changes: 2 additions & 5 deletions sparse/tests/test_coo.py
Original file line number Diff line number Diff line change
Expand Up @@ -1382,7 +1382,6 @@ def test_create_with_lists_of_tuples():


def test_sizeof():
import sys
x = np.eye(100)
y = COO.from_numpy(x)

Expand Down Expand Up @@ -1832,7 +1831,7 @@ def test_prod_along_axis():
assert_eq(s2.prod(axis=0), x2.prod(axis=0))


class TestRoll(object):
class TestRoll:

# test on 1d array #
@pytest.mark.parametrize('shift', [0, 2, -2, 20, -20])
Expand Down Expand Up @@ -1920,7 +1919,7 @@ def test_clip():
assert_eq(out, x.clip(min=1, max=3))


class TestFailFillValue(object):
class TestFailFillValue:
# Check failed fill_value op
def test_nonzero_fv(self):
xs = sparse.random((2, 3), density=0.5, fill_value=1)
Expand Down Expand Up @@ -2054,7 +2053,6 @@ def test_out_dtype():
np.positive(a.todense(), out=b.todense(), dtype='float64').dtype


@pytest.mark.skipif(sys.version_info[0] == 2, reason='Test won\'t run on Py2.')
def test_failed_densification():
import os
from importlib import reload
Expand All @@ -2072,7 +2070,6 @@ def test_failed_densification():
reload(sparse)


@pytest.mark.skipif(sys.version_info[0] == 2, reason='Test won\'t run on Py2.')
def test_warn_on_too_dense():
import os
from importlib import reload
Expand Down
3 changes: 1 addition & 2 deletions sparse/tests/test_dok.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import pytest

import numpy as np
import six

import sparse
from sparse import DOK
Expand Down Expand Up @@ -72,7 +71,7 @@ def test_construct(shape, data):
s = DOK(shape, data)
x = np.zeros(shape, dtype=s.dtype)

for c, d in six.iteritems(data):
for c, d in data.items():
x[c] = d

assert_eq(x, s)
Expand Down
5 changes: 1 addition & 4 deletions sparse/utils.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
import functools
try:
from collections.abc import Iterable
except (AttributeError, ImportError):
from collections import Iterable
from collections.abc import Iterable
from numbers import Integral

import numpy as np
Expand Down
4 changes: 2 additions & 2 deletions tox.ini
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
[tox]
envlist = py27,py36
envlist = py36, py37
[testenv]
commands=
py.test {posargs}
pytest {posargs}
extras=
tests
tox