This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author alegonz
Recipients abarry, alegonz, levkivskyi, steven.daprano
Date 2019-06-09.06:03:12
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1560060192.99.0.728589451468.issue28869@roundup.psfhosted.org>
In-reply-to
Content
Hello, I would like to add further on this issue.

(I'm new to bpo. Please advise if this report could be better)

Issue
-----

Pickling breaks when attempting to dump an instance of a class that was defined by calling ABCMeta directly, because it attempts to look for the class in `abc` rather than the module the class was defined in.

Below is a short snippet to reproduce the issue (my environment is Python 3.7.3 on Ubuntu 16.04)

>>> import pickle
>>> from abc import ABCMeta

>>> class Foo(metaclass=ABCMeta):
>>>     pass

>>> Bar = ABCMeta('Bar', (), {})

>>> foo = Foo()
>>> bar = Bar()

>>> foo_p = pickle.dumps(foo)  # OK
>>> bar_p = pickle.dumps(bar)  # PicklingError: Can't pickle <class 'abc.Bar'>: attribute lookup Bar on abc failed

I encountered this issue when working on a class factory to define classes dynamically. You can work around it if you smuggle `{'__module__': __name__}` when calling the metaclass, e.g.:

>>> Qux = ABCMeta('Qux', (), {'__module__': __name__})
>>> qux = Qux()
>>> qux_p = pickle.dumps(qux)  # OK

Apparently others have also stumbled upon this ABCMeta behavior before: https://stackoverflow.com/q/49457441

Some ideas to solve this
------------------------

A. Steven's proposal seems that could work (I haven't tested it myself yet though).
    - This, however, would be limited to ABCMeta. Any other metaclass subclassed from type would have to include that workaround too for it to play well with pickle, which leads to,

B. Do A. and include in the documentation some recipe that shows this workaround when subclassing from type.

C. Implement A. in type itself. (Maybe around here? https://github.com/python/cpython/blob/master/Objects/typeobject.c#L2603)
    - I'm not familiar with the internals of CPython, but I guess this would be the nuclear option.

If any of above ideas (or some other idea that could come up upon discussion) seems sensible, please allow me to work on it. I'd be happy to contribute :)
History
Date User Action Args
2019-06-09 06:03:13alegonzsetrecipients: + alegonz, steven.daprano, levkivskyi, abarry
2019-06-09 06:03:12alegonzsetmessageid: <1560060192.99.0.728589451468.issue28869@roundup.psfhosted.org>
2019-06-09 06:03:12alegonzlinkissue28869 messages
2019-06-09 06:03:12alegonzcreate