68

In Python 3.3 "abstract base classes" in collections (like MutableMapping or MutableSequence) were moved to second-level module collections.abc. So in Python 3.3+ the real type is collections.abc.MutableMapping and so on. Documentation states that the old alias names (e.g. collections.MutableMapping) will be available up to Python 3.7 (currently the latest version), however in 3.8 these aliases will be removed.

Current version of Python 3.7 even produces a warning when you use the alias names:

./scripts/generateBoard.py:145: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated, and in 3.8 it will stop working
  elif isinstance(value, (collections.MutableMapping, collections.MutableSequence)) == True:

In python 2.7 there is no collections.abc.

How can Python script handle this difference in the most convenient way, when it is meant to be used with (almost) any Python version? I'm looking for a solution which would ideally solve this mess in one central place, without having to use try: ... except: ... all over the script everywhere I need this type?

JJJ
  • 32,902
  • 20
  • 89
  • 102
Freddie Chopin
  • 8,440
  • 2
  • 28
  • 58

4 Answers4

67

Place this at the top of the script:

import collections

try:
    collectionsAbc = collections.abc
except AttributeError:
    collectionsAbc = collections

Then change all prefixes of the abstract base types, e.g. change collections.abc.MutableMapping or collections.MutableMapping to collectionsAbc.MutableMapping.

Alternatively, import what you require in the script at the top in a single place:

try:
    from collections.abc import Callable  # noqa
except ImportError:
    from collections import Callable  # noqa
geographika
  • 6,458
  • 4
  • 38
  • 56
Freddie Chopin
  • 8,440
  • 2
  • 28
  • 58
  • 18
    The second form is actually preferable - as when one finally give up Python 2, it is just a matter of remvoing the try/ block . The other recipe adds and additional intermediate name that would remain as legacy in the code. – jsbueno Jun 07 '19 at 21:44
  • 1
    @jsbueno On one hand I fully agree with your astute observation concerning the second form, however, I can envision a readability benefit from the first form, depending on the number of imports you have hanging out at the top of the file! FWIW, I'm using the second form ;-) – Jason R Stevens CFA Jun 03 '20 at 13:50
5

Looks like fresh version of the six module have collections_abc alias, so you can use:

from six.moves import collections_abc
Alexey Shrub
  • 1,216
  • 13
  • 22
5

One way to solve this is to simply try to get abc from collections, else assume the members of abc are already in collections.

import collections                                         
collections_abc = getattr(collections, 'abc', collections)
jvdillon
  • 645
  • 7
  • 7
  • 3
    Please don't post only code as answer, but also provide an explanation what your code does and how it solves the problem of the question. Answers with an explanation are usually more helpful and of better quality, and are more likely to attract upvotes. – Mark Rotteveel Jul 12 '20 at 08:50
1

I was getting error like this:

C:\Users\gsc-30431\Anaconda3\lib\site-packages\unittest2\compatibility.py:148
  C:\Users\gsc-30431\Anaconda3\lib\site-packages\unittest2\compatibility.py:148: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is depr
ecated since Python 3.3,and in 3.9 it will stop working
    class ChainMap(collections.MutableMapping):

-- Docs: https://docs.pytest.org/en/latest/warnings.html

enter image description here

SO i opened the File Compatibility.py by visiting the path showing in the error above! and Searched there the code where this Collections package is being used and Changed the previous line i.e:

class ChainMap(collections.MutableMapping):

to new Line:

class ChainMap(collections.abc.MutableMapping):

Screenshot: enter image description here

Just by adding .abc has solved my problem and i'm not getting warning anymore!

Amar Kumar
  • 2,392
  • 2
  • 25
  • 33
  • 1
    I just tried the same thing and it worked for me. With that said, what did we just do? I'm trying to make sure this isn't going to cause any issue in the future. – Oliver Apr 06 '21 at 14:44
  • 1
    I have not got any issues from the past 8 months. Will search for some other solution in future if it will create any problem. – Amar Kumar Apr 07 '21 at 03:33