Skip to content

Commit c09352c

Browse files
rthamueller
authored andcommitted
[MRG] Fix DeprecationWarning due to collections.abc in Python 3.7 (scikit-learn#11431)
Closes scikit-learn#11121 This PR removes the deprecation warning about ABC being moved from `collections` to `collections.abc` when importing scikit-learn in Python 3.7. In the end, I put `collections.abc.{Sequence, Iterable, Mapping, Sized}` in the namespace of `sklearn.utils.fixes`. This was the simplest way I could find, and while it has the drawback of obfuscating the real module name, other approached appeared more problematic and a similar approach is currently used e.g. for `utils.fixes.signature` which is an alias for `inspect.signature`. We can't just patch six with benjaminp/six#241, because sklearn uses six from 5 years ago, which would need updating and I'm not sure if it could have side effects (e.g. for pickling backward compatibility etc). **Edit**: This adds a test checking that generally no warnings are raised when importing scikit-learn top-level modules.
1 parent 91bfca6 commit c09352c

File tree

12 files changed

+72
-16
lines changed

12 files changed

+72
-16
lines changed

sklearn/covariance/graph_lasso_.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,11 @@
1919
from ..exceptions import ConvergenceWarning
2020
from ..utils.validation import check_random_state, check_array
2121
from ..utils import deprecated
22+
from ..utils.fixes import _Sequence as Sequence
2223
from ..linear_model import lars_path
2324
from ..linear_model import cd_fast
2425
from ..model_selection import check_cv, cross_val_score
2526
from ..externals.joblib import Parallel, delayed
26-
import collections
2727

2828

2929
# Helper functions to compute the objective and dual objective functions
@@ -608,7 +608,7 @@ def fit(self, X, y=None):
608608
n_alphas = self.alphas
609609
inner_verbose = max(0, self.verbose - 1)
610610

611-
if isinstance(n_alphas, collections.Sequence):
611+
if isinstance(n_alphas, Sequence):
612612
alphas = self.alphas
613613
n_refinements = 1
614614
else:
@@ -684,7 +684,7 @@ def fit(self, X, y=None):
684684
alpha_1 = path[best_index - 1][0]
685685
alpha_0 = path[best_index + 1][0]
686686

687-
if not isinstance(n_alphas, collections.Sequence):
687+
if not isinstance(n_alphas, Sequence):
688688
alphas = np.logspace(np.log10(alpha_1), np.log10(alpha_0),
689689
n_alphas + 2)
690690
alphas = alphas[1:-1]

sklearn/datasets/samples_generator.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@
1111
import numpy as np
1212
from scipy import linalg
1313
import scipy.sparse as sp
14-
from collections import Iterable
1514

1615
from ..preprocessing import MultiLabelBinarizer
1716
from ..utils import check_array, check_random_state
1817
from ..utils import shuffle as util_shuffle
18+
from ..utils.fixes import _Iterable as Iterable
1919
from ..utils.random import sample_without_replacement
2020
from ..externals import six
2121
map = six.moves.map

sklearn/feature_extraction/dict_vectorizer.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
# License: BSD 3 clause
44

55
from array import array
6-
from collections import Mapping
76
from operator import itemgetter
87

98
import numpy as np
@@ -13,6 +12,7 @@
1312
from ..externals import six
1413
from ..externals.six.moves import xrange
1514
from ..utils import check_array, tosequence
15+
from ..utils.fixes import _Mapping as Mapping
1616

1717

1818
def _tosequence(X):

sklearn/feature_extraction/tests/test_text.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@
3333
clean_warning_registry, ignore_warnings,
3434
SkipTest, assert_raises,
3535
assert_allclose_dense_sparse)
36-
37-
from collections import defaultdict, Mapping
36+
from sklearn.utils.fixes import _Mapping as Mapping
37+
from collections import defaultdict
3838
from functools import partial
3939
import pickle
4040
from io import StringIO

sklearn/metrics/scorer.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
# License: Simplified BSD
2020

2121
from abc import ABCMeta
22-
from collections import Iterable
2322

2423
import numpy as np
2524

@@ -40,6 +39,7 @@
4039
from .cluster import fowlkes_mallows_score
4140

4241
from ..utils.multiclass import type_of_target
42+
from ..utils.fixes import _Iterable as Iterable
4343
from ..externals import six
4444
from ..base import is_regressor
4545

sklearn/model_selection/_search.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
# License: BSD 3 clause
1414

1515
from abc import ABCMeta, abstractmethod
16-
from collections import Mapping, namedtuple, defaultdict, Sequence, Iterable
16+
from collections import namedtuple, defaultdict
1717
from functools import partial, reduce
1818
from itertools import product
1919
import operator
@@ -34,6 +34,8 @@
3434
from ..utils import check_random_state
3535
from ..utils.fixes import sp_version
3636
from ..utils.fixes import MaskedArray
37+
from ..utils.fixes import _Mapping as Mapping, _Sequence as Sequence
38+
from ..utils.fixes import _Iterable as Iterable
3739
from ..utils.random import sample_without_replacement
3840
from ..utils.validation import indexable, check_is_fitted
3941
from ..utils.metaestimators import if_delegate_has_method

sklearn/model_selection/_split.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515

1616
import warnings
1717
from itertools import chain, combinations
18-
from collections import Iterable
1918
from math import ceil, floor
2019
import numbers
2120
from abc import ABCMeta, abstractmethod
@@ -29,6 +28,7 @@
2928
from ..externals.six import with_metaclass
3029
from ..externals.six.moves import zip
3130
from ..utils.fixes import signature, comb
31+
from ..utils.fixes import _Iterable as Iterable
3232
from ..base import _pprint
3333

3434
__all__ = ['BaseCrossValidator',

sklearn/model_selection/tests/test_search.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
"""Test the search module"""
22

3-
from collections import Iterable, Sized
43
from sklearn.externals.six.moves import cStringIO as StringIO
54
from sklearn.externals.six.moves import xrange
65
from itertools import chain, product
@@ -15,6 +14,7 @@
1514

1615
from sklearn.utils.fixes import sp_version
1716
from sklearn.utils.fixes import PY3_OR_LATER
17+
from sklearn.utils.fixes import _Iterable as Iterable, _Sized as Sized
1818
from sklearn.utils.testing import assert_equal
1919
from sklearn.utils.testing import assert_not_equal
2020
from sklearn.utils.testing import assert_raises

sklearn/tests/test_init.py

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,18 @@
11
# Basic unittests to test functioning of module's top-level
22

3-
__author__ = 'Yaroslav Halchenko'
4-
__license__ = 'BSD'
3+
import subprocess
4+
5+
import pkgutil
56

7+
import pytest
68

9+
import sklearn
710
from sklearn.utils.testing import assert_equal
811

12+
__author__ = 'Yaroslav Halchenko'
13+
__license__ = 'BSD'
14+
15+
916
try:
1017
from sklearn import * # noqa
1118
_top_import_error = None
@@ -18,3 +25,37 @@ def test_import_skl():
1825
# "import *" is discouraged outside of the module level, hence we
1926
# rely on setting up the variable above
2027
assert_equal(_top_import_error, None)
28+
29+
30+
def test_import_sklearn_no_warnings():
31+
# Test that importing scikit-learn main modules doesn't raise any warnings.
32+
33+
try:
34+
pkgs = pkgutil.iter_modules(path=sklearn.__path__, prefix='sklearn.')
35+
import_modules = '; '.join(['import ' + modname
36+
for _, modname, _ in pkgs
37+
if (not modname.startswith('_') and
38+
# add deprecated top level modules
39+
# below to ignore them
40+
modname not in [])])
41+
42+
message = subprocess.check_output(['python', '-Wdefault',
43+
'-c', import_modules],
44+
stderr=subprocess.STDOUT)
45+
message = message.decode("utf-8")
46+
message = '\n'.join([line for line in message.splitlines()
47+
if not (
48+
# ignore ImportWarning due to Cython
49+
"ImportWarning" in line or
50+
# ignore DeprecationWarning due to pytest
51+
"pytest" in line or
52+
# ignore DeprecationWarnings due to
53+
# numpy.oldnumeric
54+
"oldnumeric" in line
55+
)])
56+
assert 'Warning' not in message
57+
assert 'Error' not in message
58+
59+
except Exception as e:
60+
pytest.skip('soft-failed test_import_sklearn_no_warnings.\n'
61+
' %s, \n %s' % (e, message))

sklearn/utils/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
"""
22
The :mod:`sklearn.utils` module includes various utilities.
33
"""
4-
from collections import Sequence
4+
55
import numbers
66

77
import numpy as np
@@ -17,6 +17,7 @@
1717
from .class_weight import compute_class_weight, compute_sample_weight
1818
from ..externals.joblib import cpu_count
1919
from ..exceptions import DataConversionWarning
20+
from ..utils.fixes import _Sequence as Sequence
2021
from .deprecation import deprecated
2122
from .. import get_config
2223

sklearn/utils/fixes.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,3 +310,16 @@ def _object_dtype_isnan(X):
310310
else:
311311
def _object_dtype_isnan(X):
312312
return np.frompyfunc(lambda x: x != x, 1, 1)(X).astype(bool)
313+
314+
315+
# To be removed once this fix is included in six
316+
try:
317+
from collections.abc import Sequence as _Sequence # noqa
318+
from collections.abc import Iterable as _Iterable # noqa
319+
from collections.abc import Mapping as _Mapping # noqa
320+
from collections.abc import Sized as _Sized # noqa
321+
except ImportError: # python <3.3
322+
from collections import Sequence as _Sequence # noqa
323+
from collections import Iterable as _Iterable # noqa
324+
from collections import Mapping as _Mapping # noqa
325+
from collections import Sized as _Sized # noqa

sklearn/utils/multiclass.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
88
"""
99
from __future__ import division
10-
from collections import Sequence
1110
from itertools import chain
1211

1312
from scipy.sparse import issparse
@@ -18,10 +17,10 @@
1817
import numpy as np
1918

2019
from ..externals.six import string_types
20+
from ..utils.fixes import _Sequence as Sequence
2121
from .validation import check_array
2222

2323

24-
2524
def _unique_multiclass(y):
2625
if hasattr(y, '__array__'):
2726
return np.unique(np.asarray(y))

0 commit comments

Comments
 (0)