Skip to content

Commit

Permalink
Fix class cell in __new__ for metaclasses (#468)
Browse files Browse the repository at this point in the history
* Fix class cell in `__new__` for metaclasses

* Python 3 super
  • Loading branch information
anivegesana authored May 8, 2022
1 parent df6ab36 commit d2f916c
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 1 deletion.
8 changes: 7 additions & 1 deletion dill/_dill.py
Original file line number Diff line number Diff line change
Expand Up @@ -1589,7 +1589,13 @@ def save_cell(pickler, obj):
log.info("# Ce3")
return
if is_dill(pickler, child=True):
postproc = next(iter(pickler._postproc.values()), None)
if id(f) in pickler._postproc:
# Already seen. Add to its postprocessing.
postproc = pickler._postproc[id(f)]
else:
# Haven't seen it. Add to the highest possible object and set its
# value as late as possible to prevent cycle.
postproc = next(iter(pickler._postproc.values()), None)
if postproc is not None:
log.info("Ce2: %s" % obj)
# _CELL_REF is defined in _shims.py to support older versions of
Expand Down
36 changes: 36 additions & 0 deletions tests/test_classdef.py
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,41 @@ def test_slots():
assert dill.pickles(Y.y)
assert dill.copy(y).y == value

def test_metaclass():
if dill._dill.PY3:
class metaclass_with_new(type):
def __new__(mcls, name, bases, ns, **kwds):
cls = super().__new__(mcls, name, bases, ns, **kwds)
assert mcls is not None
assert cls.method(mcls)
return cls
def method(cls, mcls):
return isinstance(cls, mcls)

l = locals()
exec("""class subclass_with_new(metaclass=metaclass_with_new):
def __new__(cls):
self = super().__new__(cls)
return self""", None, l)
subclass_with_new = l['subclass_with_new']
else:
class metaclass_with_new(type):
def __new__(mcls, name, bases, ns, **kwds):
cls = super(mcls, metaclass_with_new).__new__(mcls, name, bases, ns, **kwds)
assert mcls is not None
assert cls.method(mcls)
return cls
def method(cls, mcls):
return isinstance(cls, mcls)

class subclass_with_new:
__metaclass__ = metaclass_with_new
def __new__(cls):
self = super(subclass_with_new, cls).__new__(cls)
return self

assert dill.copy(subclass_with_new())


if __name__ == '__main__':
test_class_instances()
Expand All @@ -227,3 +262,4 @@ def test_slots():
test_array_subclass()
test_method_decorator()
test_slots()
test_metaclass()

0 comments on commit d2f916c

Please sign in to comment.