Do not copy __weakref__ from original _cls_dict (#410)

self._cls_dict["__weakref__"] holds a reference to self._cls, preventing
self._cls from being released after the new, slots-enabled class is
returned.

Fixes #407
This commit is contained in:
George Macon 2018-07-28 06:24:53 -04:00 committed by Hynek Schlawack
parent 6f3f4904be
commit 4c41099fb8
3 changed files with 22 additions and 1 deletions

View File

@ -0,0 +1 @@
Fixed a reference leak where the original class would remain live after being replaced when ``slots=True`` is set.

View File

@ -493,7 +493,7 @@ class _ClassBuilder(object):
cd = {
k: v
for k, v in iteritems(self._cls_dict)
if k not in tuple(self._attr_names) + ("__dict__",)
if k not in tuple(self._attr_names) + ("__dict__", "__weakref__")
}
# We only add the names of attributes that aren't inherited.

View File

@ -5,6 +5,7 @@ Tests for `attr._make`.
from __future__ import absolute_import, division, print_function
import copy
import gc
import inspect
import itertools
import sys
@ -1250,6 +1251,25 @@ class TestClassBuilder(object):
assert C() == copy.deepcopy(C())
def test_no_references_to_original(self):
"""
When subclassing a slots class, there are no stray references to the
original class.
"""
@attr.s(slots=True)
class C(object):
pass
@attr.s(slots=True)
class C2(C):
pass
# The original C2 is in a reference cycle, so force a collect:
gc.collect()
assert [C2] == C.__subclasses__()
class TestMakeCmp:
"""