Author: Armin Rigo <[email protected]>
Branch: gc-del
Changeset: r63550:ea7053cee8b3
Date: 2013-04-22 17:32 +0200
http://bitbucket.org/pypy/pypy/changeset/ea7053cee8b3/
Log: Fix old-style classes for the new model of __del__
diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -26,7 +26,7 @@
class W_Root(object):
"""This is the abstract root class of all wrapped objects that live
in a 'normal' object space like StdObjSpace."""
- __slots__ = ()
+ _attrs_ = ()
_settled_ = True
user_overridden_class = False
@@ -220,7 +220,7 @@
class Wrappable(W_Root):
"""A subclass of Wrappable is an internal, interpreter-level class
that can nevertheless be exposed at application-level by space.wrap()."""
- __slots__ = ()
+ _attrs_ = ()
_settled_ = True
def __spacebind__(self, space):
diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py
--- a/pypy/interpreter/typedef.py
+++ b/pypy/interpreter/typedef.py
@@ -638,9 +638,6 @@
def make_weakref_descr(cls):
"""Make instances of the Wrappable subclass 'cls' weakrefable.
This returns the '__weakref__' desctriptor to use for the TypeDef.
- Note that if the class also defines a custom '__del__', the
- __del__ should call self.clear_all_weakrefs() before it clears
- the resources used by the object.
"""
# force the interface into the given cls
def getweakref(self):
diff --git a/pypy/module/__builtin__/interp_classobj.py
b/pypy/module/__builtin__/interp_classobj.py
--- a/pypy/module/__builtin__/interp_classobj.py
+++ b/pypy/module/__builtin__/interp_classobj.py
@@ -6,7 +6,7 @@
from pypy.interpreter.typedef import GetSetProperty, descr_get_dict,
descr_set_dict
from rpython.rlib.objectmodel import compute_identity_hash
from rpython.rlib.debug import make_sure_not_resized
-from rpython.rlib import jit
+from rpython.rlib import rgc, jit
def raise_type_err(space, argument, expected, w_obj):
@@ -57,10 +57,7 @@
def instantiate(self, space):
cache = space.fromcache(Cache)
- if self.lookup(space, '__del__') is not None:
- w_inst = cache.cls_with_del(space, self)
- else:
- w_inst = cache.cls_without_del(space, self)
+ w_inst = cache.class_of_instance(space, self)
return w_inst
def getdict(self, space):
@@ -152,11 +149,6 @@
elif name == "__bases__":
self.setbases(space, w_value)
return
- elif name == "__del__":
- if self.lookup(space, name) is None:
- msg = ("a __del__ method added to an existing class will "
- "not be called")
- space.warn(space.wrap(msg), space.w_RuntimeWarning)
space.setitem(self.w_dict, w_attr, w_value)
def descr_delattr(self, space, w_attr):
@@ -204,11 +196,10 @@
class Cache:
def __init__(self, space):
from pypy.interpreter.typedef import _usersubclswithfeature
- # evil
- self.cls_without_del = _usersubclswithfeature(
+ # evil: "class_of_instance" is a subclass of W_InstanceObject
+ # which has additionally the "dict" and "weakref" capabilities
+ self.class_of_instance = _usersubclswithfeature(
space.config, W_InstanceObject, "dict", "weakref")
- self.cls_with_del = _usersubclswithfeature(
- space.config, self.cls_without_del, "del")
def class_descr_call(space, w_self, __args__):
@@ -321,6 +312,8 @@
self.user_setup(space, space.gettypeobject(self.typedef))
assert isinstance(w_class, W_ClassObject)
self.w_class = w_class
+ if self.getattr_from_class(space, '__del__') is not None:
+ rgc.register_finalizer(self.finalizer)
def user_setup(self, space, w_subtype):
self.space = space
@@ -391,13 +384,8 @@
if name == '__class__':
self.set_oldstyle_class(space, w_value)
return
- if name == '__del__' and w_meth is None:
- cache = space.fromcache(Cache)
- if (not isinstance(self, cache.cls_with_del)
- and self.getdictvalue(space, '__del__') is None):
- msg = ("a __del__ method added to an instance with no "
- "__del__ in the class will not be called")
- space.warn(space.wrap(msg), space.w_RuntimeWarning)
+ if name == '__del__':
+ rgc.register_finalizer(self.finalizer)
if w_meth is not None:
space.call_function(w_meth, w_name, w_value)
else:
@@ -700,9 +688,8 @@
space.wrap("instance has no next() method"))
return space.call_function(w_func)
- def descr_del(self, space):
- # Note that this is called from executioncontext.UserDelAction
- # via the space.userdel() method.
+ def finalizer(self):
+ space = self.space
w_func = self.getdictvalue(space, '__del__')
if w_func is None:
w_func = self.getattr_from_class(space, '__del__')
@@ -783,7 +770,6 @@
__pow__ = interp2app(W_InstanceObject.descr_pow),
__rpow__ = interp2app(W_InstanceObject.descr_rpow),
next = interp2app(W_InstanceObject.descr_next),
- __del__ = interp2app(W_InstanceObject.descr_del),
__exit__ = interp2app(W_InstanceObject.descr_exit),
__dict__ = dict_descr,
**rawdict
diff --git a/pypy/module/__builtin__/test/test_classobj.py
b/pypy/module/__builtin__/test/test_classobj.py
--- a/pypy/module/__builtin__/test/test_classobj.py
+++ b/pypy/module/__builtin__/test/test_classobj.py
@@ -670,6 +670,22 @@
gc.collect()
gc.collect()
assert l == [1, 1]
+ class C:
+ pass
+ c = C()
+ c.__del__ = lambda: l.append(2)
+ c = None
+ gc.collect()
+ gc.collect()
+ gc.collect()
+ assert l == [1, 1, 2]
+ d = A()
+ d.__del__ = lambda: l.append(3)
+ d = None
+ gc.collect()
+ gc.collect()
+ gc.collect()
+ assert l == [1, 1, 2, 3]
def test_catch_attributeerror_of_descriptor(self):
def booh(self):
@@ -745,21 +761,16 @@
assert Y() != X()
def test_assignment_to_del(self):
- import sys
- if not hasattr(sys, 'pypy_objspaceclass'):
- skip("assignment to __del__ doesn't give a warning in CPython")
-
+ # assignment to __del__ no longer gives a warning
import warnings
-
warnings.simplefilter('error', RuntimeWarning)
try:
class X:
pass
- raises(RuntimeWarning, "X.__del__ = lambda self: None")
+ X.__del__ = lambda self: None
class Y:
pass
- raises(RuntimeWarning, "Y().__del__ = lambda self: None")
- # but the following works
+ Y().__del__ = lambda self: None
class Z:
def __del__(self):
pass
diff --git a/pypy/module/_cffi_backend/cdataobj.py
b/pypy/module/_cffi_backend/cdataobj.py
--- a/pypy/module/_cffi_backend/cdataobj.py
+++ b/pypy/module/_cffi_backend/cdataobj.py
@@ -318,7 +318,6 @@
cdata = lltype.malloc(rffi.CCHARP.TO, size, flavor='raw', zero=True)
W_CData.__init__(self, space, cdata, ctype)
- @rgc.must_be_light_finalizer
def __del__(self):
lltype.free(self._cdata, flavor='raw')
diff --git a/pypy/module/_cffi_backend/libraryobj.py
b/pypy/module/_cffi_backend/libraryobj.py
--- a/pypy/module/_cffi_backend/libraryobj.py
+++ b/pypy/module/_cffi_backend/libraryobj.py
@@ -7,6 +7,7 @@
from rpython.rtyper.lltypesystem import rffi
from rpython.rlib.rdynload import DLLHANDLE, dlopen, dlsym, dlclose,
DLOpenError
+from rpython.rlib import rgc
from pypy.module._cffi_backend.cdataobj import W_CData
from pypy.module._cffi_backend.ctypeobj import W_CType
@@ -28,8 +29,9 @@
"cannot load library %s: %s",
filename, e.msg)
self.name = filename
+ rgc.register_finalizer(self.finalizer)
- def __del__(self):
+ def finalizer(self):
h = self.handle
if h != rffi.cast(DLLHANDLE, 0):
self.handle = rffi.cast(DLLHANDLE, 0)
diff --git a/pypy/module/_file/interp_file.py b/pypy/module/_file/interp_file.py
--- a/pypy/module/_file/interp_file.py
+++ b/pypy/module/_file/interp_file.py
@@ -2,7 +2,7 @@
import os
import stat
import errno
-from rpython.rlib import streamio
+from rpython.rlib import streamio, rgc
from rpython.rlib.rarithmetic import r_longlong
from rpython.rlib.rstring import StringBuilder
from pypy.module._file.interp_stream import W_AbstractStream, StreamErrors
@@ -38,7 +38,7 @@
def __init__(self, space):
self.space = space
- self.register_finalizer()
+ rgc.register_finalizer(self.finalizer)
def finalizer(self):
try:
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit