[Python-checkins] bpo-25988: Emit a warning when use or import ABCs from 'collections'. (GH-5734)

Ivan Levkivskyi webhook-mailer at python.org
Sun Feb 18 12:41:01 EST 2018


https://github.com/python/cpython/commit/0442de5ad7835814d60f46c22a22942abb101aef
commit: 0442de5ad7835814d60f46c22a22942abb101aef
branch: 3.7
author: Ivan Levkivskyi <levkivskyi at gmail.com>
committer: GitHub <noreply at github.com>
date: 2018-02-18T17:40:59Z
summary:

bpo-25988: Emit a warning when use or import ABCs from 'collections'. (GH-5734)

files:
M Lib/collections/__init__.py
M Modules/_decimal/_decimal.c

diff --git a/Lib/collections/__init__.py b/Lib/collections/__init__.py
index c481fe2f2012..9a753db71cae 100644
--- a/Lib/collections/__init__.py
+++ b/Lib/collections/__init__.py
@@ -17,16 +17,7 @@
 __all__ = ['deque', 'defaultdict', 'namedtuple', 'UserDict', 'UserList',
             'UserString', 'Counter', 'OrderedDict', 'ChainMap']
 
-# For backwards compatibility, continue to make the collections ABCs
-# through Python 3.6 available through the collections module.
-# Note, no new collections ABCs were added in Python 3.7
 import _collections_abc
-from _collections_abc import (AsyncGenerator, AsyncIterable, AsyncIterator,
-    Awaitable, ByteString, Callable, Collection, Container, Coroutine,
-    Generator, Hashable, ItemsView, Iterable, Iterator, KeysView, Mapping,
-    MappingView, MutableMapping, MutableSequence, MutableSet, Reversible,
-    Sequence, Set, Sized, ValuesView)
-
 from operator import itemgetter as _itemgetter, eq as _eq
 from keyword import iskeyword as _iskeyword
 import sys as _sys
@@ -40,7 +31,7 @@
 except ImportError:
     pass
 else:
-    MutableSequence.register(deque)
+    _collections_abc.MutableSequence.register(deque)
 
 try:
     from _collections import defaultdict
@@ -48,22 +39,37 @@
     pass
 
 
+def __getattr__(name):
+    # For backwards compatibility, continue to make the collections ABCs
+    # through Python 3.6 available through the collections module.
+    # Note, no new collections ABCs were added in Python 3.7
+    if name in _collections_abc.__all__:
+        obj = getattr(_collections_abc, name)
+        import warnings
+        warnings.warn("Using or importing the ABCs from 'collections' instead "
+                      "of from 'collections.abc' is deprecated, "
+                      "and in 3.8 it will stop working",
+                      DeprecationWarning, stacklevel=2)
+        globals()[name] = obj
+        return obj
+    raise AttributeError(f'module {__name__!r} has no attribute {name!r}')
+
 ################################################################################
 ### OrderedDict
 ################################################################################
 
-class _OrderedDictKeysView(KeysView):
+class _OrderedDictKeysView(_collections_abc.KeysView):
 
     def __reversed__(self):
         yield from reversed(self._mapping)
 
-class _OrderedDictItemsView(ItemsView):
+class _OrderedDictItemsView(_collections_abc.ItemsView):
 
     def __reversed__(self):
         for key in reversed(self._mapping):
             yield (key, self._mapping[key])
 
-class _OrderedDictValuesView(ValuesView):
+class _OrderedDictValuesView(_collections_abc.ValuesView):
 
     def __reversed__(self):
         for key in reversed(self._mapping):
@@ -215,7 +221,7 @@ def __sizeof__(self):
         size += sizeof(self.__root) * n         # proxy objects
         return size
 
-    update = __update = MutableMapping.update
+    update = __update = _collections_abc.MutableMapping.update
 
     def keys(self):
         "D.keys() -> a set-like object providing a view on D's keys"
@@ -229,7 +235,7 @@ def values(self):
         "D.values() -> an object providing a view on D's values"
         return _OrderedDictValuesView(self)
 
-    __ne__ = MutableMapping.__ne__
+    __ne__ = _collections_abc.MutableMapping.__ne__
 
     __marker = object()
 
@@ -636,7 +642,7 @@ def update(*args, **kwds):
             raise TypeError('expected at most 1 arguments, got %d' % len(args))
         iterable = args[0] if args else None
         if iterable is not None:
-            if isinstance(iterable, Mapping):
+            if isinstance(iterable, _collections_abc.Mapping):
                 if self:
                     self_get = self.get
                     for elem, count in iterable.items():
@@ -673,7 +679,7 @@ def subtract(*args, **kwds):
         iterable = args[0] if args else None
         if iterable is not None:
             self_get = self.get
-            if isinstance(iterable, Mapping):
+            if isinstance(iterable, _collections_abc.Mapping):
                 for elem, count in iterable.items():
                     self[elem] = self_get(elem, 0) - count
             else:
@@ -875,7 +881,7 @@ def __iand__(self, other):
 ###  ChainMap
 ########################################################################
 
-class ChainMap(MutableMapping):
+class ChainMap(_collections_abc.MutableMapping):
     ''' A ChainMap groups multiple dicts (or other mappings) together
     to create a single, updateable view.
 
@@ -986,7 +992,7 @@ def clear(self):
 ### UserDict
 ################################################################################
 
-class UserDict(MutableMapping):
+class UserDict(_collections_abc.MutableMapping):
 
     # Start by filling-out the abstract methods
     def __init__(*args, **kwargs):
@@ -1053,7 +1059,7 @@ def fromkeys(cls, iterable, value=None):
 ### UserList
 ################################################################################
 
-class UserList(MutableSequence):
+class UserList(_collections_abc.MutableSequence):
     """A more or less complete user-defined wrapper around list objects."""
     def __init__(self, initlist=None):
         self.data = []
@@ -1126,7 +1132,7 @@ def extend(self, other):
 ### UserString
 ################################################################################
 
-class UserString(Sequence):
+class UserString(_collections_abc.Sequence):
     def __init__(self, seq):
         if isinstance(seq, str):
             self.data = seq
diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c
index fddb39ef652a..5bce780cb7fb 100644
--- a/Modules/_decimal/_decimal.c
+++ b/Modules/_decimal/_decimal.c
@@ -5521,6 +5521,7 @@ PyInit__decimal(void)
     PyObject *numbers = NULL;
     PyObject *Number = NULL;
     PyObject *collections = NULL;
+    PyObject *collections_abc = NULL;
     PyObject *MutableMapping = NULL;
     PyObject *obj = NULL;
     DecCondMap *cm;
@@ -5595,7 +5596,8 @@ PyInit__decimal(void)
     Py_CLEAR(obj);
 
     /* MutableMapping */
-    ASSIGN_PTR(MutableMapping, PyObject_GetAttrString(collections,
+    ASSIGN_PTR(collections_abc, PyImport_ImportModule("collections.abc"));
+    ASSIGN_PTR(MutableMapping, PyObject_GetAttrString(collections_abc,
                                                       "MutableMapping"));
     /* Create SignalDict type */
     ASSIGN_PTR(PyDecSignalDict_Type,
@@ -5606,6 +5608,7 @@ PyInit__decimal(void)
 
     /* Done with collections, MutableMapping */
     Py_CLEAR(collections);
+    Py_CLEAR(collections_abc);
     Py_CLEAR(MutableMapping);
 
 
@@ -5765,6 +5768,7 @@ PyInit__decimal(void)
     Py_CLEAR(Number); /* GCOV_NOT_REACHED */
     Py_CLEAR(Rational); /* GCOV_NOT_REACHED */
     Py_CLEAR(collections); /* GCOV_NOT_REACHED */
+    Py_CLEAR(collections_abc); /* GCOV_NOT_REACHED */
     Py_CLEAR(MutableMapping); /* GCOV_NOT_REACHED */
     Py_CLEAR(SignalTuple); /* GCOV_NOT_REACHED */
     Py_CLEAR(DecimalTuple); /* GCOV_NOT_REACHED */



More information about the Python-checkins mailing list