[pypy-svn] r52118 - in pypy/dist/pypy/module/__builtin__: . test
arigo at codespeak.net
arigo at codespeak.net
Mon Mar 3 20:32:56 CET 2008
Author: arigo
Date: Mon Mar 3 20:32:54 2008
New Revision: 52118
Modified:
pypy/dist/pypy/module/__builtin__/interp_classobj.py
pypy/dist/pypy/module/__builtin__/test/test_classobj.py
Log:
issue334 in-progress
Warn when adding a __del__ to an old-style class.
Modified: pypy/dist/pypy/module/__builtin__/interp_classobj.py
==============================================================================
--- pypy/dist/pypy/module/__builtin__/interp_classobj.py (original)
+++ pypy/dist/pypy/module/__builtin__/interp_classobj.py Mon Mar 3 20:32:54 2008
@@ -2,7 +2,7 @@
from pypy.interpreter.error import OperationError
from pypy.interpreter.gateway import ObjSpace, W_Root, NoneNotWrapped, applevel
from pypy.interpreter.gateway import interp2app, ObjSpace
-from pypy.interpreter.typedef import TypeDef, GetSetProperty, make_weakref_descr
+from pypy.interpreter.typedef import TypeDef, make_weakref_descr
from pypy.interpreter.argument import Arguments
from pypy.interpreter.baseobjspace import Wrappable
from pypy.rlib.rarithmetic import r_uint, intmask
@@ -15,6 +15,14 @@
raise OperationError(space.w_TypeError,
w_error)
+def unwrap_attr(space, w_attr):
+ try:
+ return space.str_w(w_attr)
+ except OperationError, e:
+ if not e.match(space, space.w_TypeError):
+ raise
+ return ""
+
def descr_classobj_new(space, w_subtype, w_name, w_bases, w_dict):
if not space.is_true(space.isinstance(w_bases, space.w_tuple)):
raise_type_err(space, 'bases', 'tuple', w_bases)
@@ -55,37 +63,14 @@
space.wrap("__dict__ must be a dictionary object"))
self.w_dict = w_dict
- def fget_dict(space, self):
- return self.w_dict
-
- def fset_dict(space, self, w_dict):
- self.setdict(space, w_dict)
-
- def fdel_dict(space, self):
- raise OperationError(
- space.w_TypeError,
- space.wrap("__dict__ must be a dictionary object"))
-
- def fget_name(space, self):
- return space.wrap(self.name)
-
- def fset_name(space, self, w_newname):
+ def setname(self, space, w_newname):
if not space.is_true(space.isinstance(w_newname, space.w_str)):
raise OperationError(
space.w_TypeError,
space.wrap("__name__ must be a string object"))
self.name = space.str_w(w_newname)
- def fdel_name(space, self):
- raise OperationError(
- space.w_TypeError,
- space.wrap("__name__ must be a string object"))
-
-
- def fget_bases(space, self):
- return space.newtuple(self.bases_w)
-
- def fset_bases(space, self, w_bases):
+ def setbases(self, space, w_bases):
# XXX in theory, this misses a check against inheritance cycles
# although on pypy we don't get a segfault for infinite
# recursion anyway
@@ -100,11 +85,6 @@
space.wrap("__bases__ items must be classes"))
self.bases_w = bases_w
- def fdel_bases(space, self):
- raise OperationError(
- space.w_TypeError,
- space.wrap("__bases__ must be a tuple object"))
-
def lookup(self, space, w_attr):
# returns w_value or interplevel None
w_result = space.finditem(self.w_dict, w_attr)
@@ -119,12 +99,8 @@
return None
def descr_getattribute(self, space, w_attr):
- try:
- name = space.str_w(w_attr)
- except OperationError, e:
- if not e.match(space, space.w_TypeError):
- raise
- else:
+ name = unwrap_attr(space, w_attr)
+ if name and name[0] == "_":
if name == "__dict__":
return self.w_dict
elif name == "__name__":
@@ -142,7 +118,42 @@
if w_descr_get is None:
return w_value
return space.call_function(w_descr_get, w_value, space.w_None, self)
-
+
+ def descr_setattr(self, space, w_attr, w_value):
+ name = unwrap_attr(space, w_attr)
+ if name and name[0] == "_":
+ if name == "__dict__":
+ self.setdict(space, w_value)
+ return
+ elif name == "__name__":
+ self.setname(space, w_value)
+ return
+ elif name == "__bases__":
+ self.setbases(space, w_value)
+ return
+ elif name == "__del__":
+ if self.lookup(space, space.wrap('__del__')) is None:
+ msg = ("a __del__ method added to an existing class "
+ "will not be called")
+ space.warn(msg, space.w_RuntimeWarning)
+ space.setitem(self.w_dict, w_attr, w_value)
+
+ def descr_delattr(self, space, w_attr):
+ name = unwrap_attr(space, w_attr)
+ if name in ("__dict__", "__name__", "__bases__"):
+ raise OperationError(
+ space.w_TypeError,
+ space.wrap("cannot delete attribute %s" % (name,)))
+ try:
+ space.delitem(self.w_dict, w_attr)
+ except OperationError, e:
+ if not e.match(space, space.w_KeyError):
+ raise
+ raise OperationError(
+ space.w_AttributeError,
+ space.wrap("class %s has no attribute %s" % (
+ self.name, space.str_w(space.str(w_attr)))))
+
def descr_call(self, space, __args__):
if self.lookup(space, space.wrap('__del__')) is not None:
w_inst = W_InstanceObjectWithDel(space, self)
@@ -185,13 +196,6 @@
W_ClassObject.typedef = TypeDef("classobj",
__new__ = interp2app(descr_classobj_new),
- __dict__ = GetSetProperty(W_ClassObject.fget_dict, W_ClassObject.fset_dict,
- W_ClassObject.fdel_dict),
- __name__ = GetSetProperty(W_ClassObject.fget_name, W_ClassObject.fset_name,
- W_ClassObject.fdel_name),
- __bases__ = GetSetProperty(W_ClassObject.fget_bases,
- W_ClassObject.fset_bases,
- W_ClassObject.fdel_bases),
__repr__ = interp2app(W_ClassObject.descr_repr,
unwrap_spec=['self', ObjSpace]),
__str__ = interp2app(W_ClassObject.descr_str,
@@ -200,6 +204,10 @@
unwrap_spec=['self', ObjSpace, Arguments]),
__getattribute__ = interp2app(W_ClassObject.descr_getattribute,
unwrap_spec=['self', ObjSpace, W_Root]),
+ __setattr__ = interp2app(W_ClassObject.descr_setattr,
+ unwrap_spec=['self', ObjSpace, W_Root, W_Root]),
+ __delattr__ = interp2app(W_ClassObject.descr_delattr,
+ unwrap_spec=['self', ObjSpace, W_Root]),
)
W_ClassObject.typedef.acceptable_as_base_class = False
Modified: pypy/dist/pypy/module/__builtin__/test/test_classobj.py
==============================================================================
--- pypy/dist/pypy/module/__builtin__/test/test_classobj.py (original)
+++ pypy/dist/pypy/module/__builtin__/test/test_classobj.py Mon Mar 3 20:32:54 2008
@@ -687,3 +687,15 @@
assert X() != 5
assert Y() != X()
+
+ def test_assignment_to_del(self):
+ import warnings
+
+ class X:
+ pass
+
+ warnings.simplefilter('error', RuntimeWarning)
+ try:
+ raises(RuntimeWarning, "X.__del__ = lambda self: None")
+ finally:
+ warnings.simplefilter('default', RuntimeWarning)
More information about the Pypy-commit
mailing list