[pypy-svn] r57072 - in pypy/branch/isinstance-refactor/pypy/module/__builtin__: . test
arigo at codespeak.net
arigo at codespeak.net
Thu Aug 7 19:02:01 CEST 2008
Author: arigo
Date: Thu Aug 7 19:02:00 2008
New Revision: 57072
Added:
pypy/branch/isinstance-refactor/pypy/module/__builtin__/abstractinst.py (contents, props changed)
pypy/branch/isinstance-refactor/pypy/module/__builtin__/test/test_abstractinst.py (contents, props changed)
Modified:
pypy/branch/isinstance-refactor/pypy/module/__builtin__/__init__.py
pypy/branch/isinstance-refactor/pypy/module/__builtin__/operation.py
Log:
The logic, more directly copied from CPython.
Modified: pypy/branch/isinstance-refactor/pypy/module/__builtin__/__init__.py
==============================================================================
--- pypy/branch/isinstance-refactor/pypy/module/__builtin__/__init__.py (original)
+++ pypy/branch/isinstance-refactor/pypy/module/__builtin__/__init__.py Thu Aug 7 19:02:00 2008
@@ -87,8 +87,8 @@
'coerce' : 'operation.coerce',
'divmod' : 'operation.divmod',
'_issubtype' : 'operation._issubtype',
- 'issubclass' : 'operation.issubclass',
- 'isinstance' : 'operation.isinstance',
+ 'issubclass' : 'abstractinst.app_issubclass',
+ 'isinstance' : 'abstractinst.app_isinstance',
'getattr' : 'operation.getattr',
'setattr' : 'operation.setattr',
'delattr' : 'operation.delattr',
@@ -151,6 +151,12 @@
# xxx hide the installer
space.delitem(self.w_dict, space.wrap(name))
del self.loaders[name]
+ # install the more general version of isinstance() & co. in the space
+ from pypy.module.__builtin__ import abstractinst as ab
+ space.abstract_isinstance_w = ab.abstract_isinstance_w.__get__(space)
+ space.abstract_issubclass_w = ab.abstract_issubclass_w.__get__(space)
+ space.abstract_isclass_w = ab.abstract_isclass_w.__get__(space)
+ space.abstract_getclass = ab.abstract_getclass.__get__(space)
def startup(self, space):
# install zipimport hook if --withmod-zipimport is used
Added: pypy/branch/isinstance-refactor/pypy/module/__builtin__/abstractinst.py
==============================================================================
--- (empty file)
+++ pypy/branch/isinstance-refactor/pypy/module/__builtin__/abstractinst.py Thu Aug 7 19:02:00 2008
@@ -0,0 +1,166 @@
+"""
+Implementation of the 'abstract instance and subclasses' protocol:
+objects can return pseudo-classes as their '__class__' attribute, and
+pseudo-classes can have a '__bases__' attribute with a tuple of other
+pseudo-classes. The standard built-in functions isinstance() and
+issubclass() follow and trust these attributes is they are present, in
+addition to checking for instances and subtypes in the normal way.
+"""
+
+from pypy.interpreter.error import OperationError
+from pypy.module.__builtin__.interp_classobj import W_ClassObject
+from pypy.module.__builtin__.interp_classobj import W_InstanceObject
+
+def _get_bases(space, w_cls):
+ """Returns 'cls.__bases__'. Returns None if there is
+ no __bases__ or if cls.__bases__ is not a tuple.
+ """
+ try:
+ w_bases = space.getattr(w_cls, space.wrap('__bases__'))
+ except OperationError, e:
+ if not e.match(space, space.w_AttributeError):
+ raise # propagate other errors
+ return None
+ if space.is_true(space.isinstance(w_bases, space.w_tuple)):
+ return w_bases
+ else:
+ return None
+
+def abstract_isclass_w(space, w_obj):
+ return _get_bases(space, w_obj) is not None
+
+def check_class(space, w_obj, msg):
+ if not abstract_isclass_w(space, w_obj):
+ raise OperationError(space.w_TypeError, space.wrap(msg))
+
+
+def abstract_getclass(space, w_obj):
+ try:
+ return space.getattr(w_obj, space.wrap('__class__'))
+ except OperationError, e:
+ if not e.match(space, space.w_AttributeError):
+ raise # propagate other errors
+ return space.type(w_obj)
+
+
+def abstract_isinstance_w(space, w_obj, w_klass_or_tuple):
+ """Implementation for the full 'isinstance(obj, klass_or_tuple)'."""
+
+ # -- case (anything, type)
+ try:
+ w_result = space.isinstance(w_obj, w_klass_or_tuple)
+ except OperationError, e: # if w_klass_or_tuple was not a type, ignore it
+ if not e.match(space, space.w_TypeError):
+ raise # propagate other errors
+ else:
+ if space.is_true(w_result):
+ return True
+ # From now on we know that w_klass_or_tuple is indeed a type.
+ # Try also to compare it with obj.__class__, if this is not
+ # the same as type(obj).
+ try:
+ w_pretendtype = space.getattr(w_obj, space.wrap('__class__'))
+ if space.is_w(w_pretendtype, space.type(w_obj)):
+ return False # common case: obj.__class__ is type(obj)
+ w_result = space.issubtype(w_pretendtype, w_klass_or_tuple)
+ except OperationError, e:
+ if e.async(space):
+ raise
+ return False # ignore most exceptions
+ else:
+ return space.is_true(w_result)
+
+ # -- case (old-style instance, old-style class)
+ oldstyleclass = space.interpclass_w(w_klass_or_tuple)
+ if isinstance(oldstyleclass, W_ClassObject):
+ oldstyleinst = space.interpclass_w(w_obj)
+ if isinstance(oldstyleinst, W_InstanceObject):
+ return oldstyleinst.w_class.is_subclass_of(oldstyleclass)
+
+ # -- case (anything, tuple)
+ if space.is_true(space.isinstance(w_klass_or_tuple, space.w_tuple)):
+ for w_klass in space.unpacktuple(w_klass_or_tuple):
+ if abstract_isinstance_w(space, w_obj, w_klass):
+ return True
+ return False
+
+ # -- case (anything, abstract-class)
+ check_class(space, w_klass_or_tuple,
+ "isinstance() arg 2 must be a class, type,"
+ " or tuple of classes and types")
+ try:
+ w_abstractclass = space.getattr(w_obj, space.wrap('__class__'))
+ except OperationError, e:
+ if e.async(space): # ignore most exceptions
+ raise
+ return False
+ else:
+ return _issubclass_recurse(space, w_abstractclass, w_klass_or_tuple)
+
+
+def _issubclass_recurse(space, w_derived, w_top):
+ """Internal helper for abstract cases. Here, w_top cannot be a tuple."""
+ if space.is_w(w_derived, w_top):
+ return True
+ w_bases = _get_bases(space, w_derived)
+ if w_bases is not None:
+ for w_base in space.unpacktuple(w_bases):
+ if _issubclass_recurse(space, w_base, w_top):
+ return True
+ return False
+
+
+def abstract_issubclass_w(space, w_derived, w_klass_or_tuple):
+ """Implementation for the full 'issubclass(derived, klass_or_tuple)'."""
+
+ # -- case (type, type)
+ try:
+ w_result = space.issubtype(w_derived, w_klass_or_tuple)
+ except OperationError, e: # if one of the args was not a type, ignore it
+ if not e.match(space, space.w_TypeError):
+ raise # propagate other errors
+ else:
+ return space.is_true(w_result)
+
+ # -- case (old-style class, old-style class)
+ oldstylederived = space.interpclass_w(w_derived)
+ if isinstance(oldstylederived, W_ClassObject):
+ oldstyleklass = space.interpclass_w(w_klass_or_tuple)
+ if isinstance(oldstyleklass, W_ClassObject):
+ return oldstylederived.is_subclass_of(oldstyleklass)
+ else:
+ check_class(space, w_derived, "issubclass() arg 1 must be a class")
+ # from here on, we are sure that w_derived is a class-like object
+
+ # -- case (class-like-object, tuple-of-classes)
+ if space.is_true(space.isinstance(w_klass_or_tuple, space.w_tuple)):
+ for w_klass in space.unpacktuple(w_klass_or_tuple):
+ if abstract_issubclass_w(w_derived, w_klass):
+ return True
+ return False
+
+ # -- case (class-like-object, abstract-class)
+ check_class(space, w_klass_or_tuple,
+ "issubclass() arg 2 must be a class, type,"
+ " or tuple of classes and types")
+ return _issubclass_recurse(space, w_derived, w_klass_or_tuple)
+
+
+# ____________________________________________________________
+# App-level interface
+
+def issubclass(space, w_cls, w_klass_or_tuple):
+ """Check whether a class 'cls' is a subclass (i.e., a derived class) of
+another class. When using a tuple as the second argument, check whether
+'cls' is a subclass of any of the classes listed in the tuple."""
+ return space.wrap(abstract_issubclass_w(space, w_cls, w_klass_or_tuple))
+
+def isinstance(space, w_obj, w_klass_or_tuple):
+ """Check whether an object is an instance of a class (or of a subclass
+thereof). When using a tuple as the second argument, check whether 'obj'
+is an instance of any of the classes listed in the tuple."""
+ return space.wrap(abstract_isinstance_w(space, w_obj, w_klass_or_tuple))
+
+# avoid namespace pollution
+app_issubclass = issubclass; del issubclass
+app_isinstance = isinstance; del isinstance
Modified: pypy/branch/isinstance-refactor/pypy/module/__builtin__/operation.py
==============================================================================
--- pypy/branch/isinstance-refactor/pypy/module/__builtin__/operation.py (original)
+++ pypy/branch/isinstance-refactor/pypy/module/__builtin__/operation.py Thu Aug 7 19:02:00 2008
@@ -220,95 +220,3 @@
function). Note that classes are callable."""
return space.callable(w_object)
-
-
-def _recursive_issubclass(space, w_cls, w_klass_or_tuple): # returns interp-level bool
- if space.is_w(w_cls, w_klass_or_tuple):
- return True
- try:
- w_bases = space.getattr(w_cls, space.wrap("__bases__"))
- except OperationError, e:
- if e.match(space, space.w_AttributeError):
- return False
- else:
- raise
- w_iterator = space.iter(w_bases)
- while True:
- try:
- w_base = space.next(w_iterator)
- except OperationError, e:
- if not e.match(space, space.w_StopIteration):
- raise
- break
- if _recursive_issubclass(space, w_base, w_klass_or_tuple):
- return True
- return False
-
-def _issubclass(space, w_cls, w_klass_or_tuple, check_cls, depth): # returns interp-level bool
- if depth == 0:
- # XXX overzealous test compliance hack
- raise OperationError(space.w_RuntimeError, space.wrap("maximum recursion depth exceeded"))
- if space.is_true(space.issubtype(space.type(w_klass_or_tuple), space.w_tuple)):
- w_iter = space.iter(w_klass_or_tuple)
- while True:
- try:
- w_klass = space.next(w_iter)
- except OperationError, e:
- if not e.match(space, space.w_StopIteration):
- raise
- break
- if _issubclass(space, w_cls, w_klass, True, depth - 1):
- return True
- return False
-
- try:
- return space.is_true(space.issubtype(w_cls, w_klass_or_tuple))
- except OperationError, e:
- if e.match(space, space.w_TypeError):
- w_bases = space.wrap('__bases__')
- if check_cls:
- try:
- space.getattr(w_cls, w_bases)
- except OperationError, e:
- if not e.match(space, space.w_AttributeError):
- raise
- raise OperationError(space.w_TypeError, space.wrap('arg 1 must be a class or type'))
- try:
- space.getattr(w_klass_or_tuple, w_bases)
- except OperationError, e:
- if not e.match(space, space.w_AttributeError):
- raise
- raise OperationError(space.w_TypeError, space.wrap('arg 2 must be a class or type or a tuple thereof'))
- return _recursive_issubclass(space, w_cls, w_klass_or_tuple)
- else:
- raise
-
-
-def issubclass(space, w_cls, w_klass_or_tuple):
- """Check whether a class 'cls' is a subclass (i.e., a derived class) of
-another class. When using a tuple as the second argument, check whether
-'cls' is a subclass of any of the classes listed in the tuple."""
- return space.wrap(issubclass_w(space, w_cls, w_klass_or_tuple))
-
-def issubclass_w(space, w_cls, w_klass_or_tuple):
- return _issubclass(space, w_cls, w_klass_or_tuple, True, space.sys.recursionlimit)
-
-
-def isinstance(space, w_obj, w_klass_or_tuple):
- """Check whether an object is an instance of a class (or of a subclass
-thereof). When using a tuple as the second argument, check whether 'obj'
-is an instance of any of the classes listed in the tuple."""
- w_objtype = space.type(w_obj)
- if issubclass_w(space, w_objtype, w_klass_or_tuple):
- return space.w_True
- try:
- w_objcls = space.getattr(w_obj, space.wrap("__class__"))
- except OperationError, e:
- if e.match(space, space.w_AttributeError):
- return space.w_False
- else:
- raise
- if space.is_w(w_objcls, w_objtype):
- return space.w_False
- else:
- return space.wrap(_issubclass(space, w_objcls, w_klass_or_tuple, False, space.sys.recursionlimit))
Added: pypy/branch/isinstance-refactor/pypy/module/__builtin__/test/test_abstractinst.py
==============================================================================
--- (empty file)
+++ pypy/branch/isinstance-refactor/pypy/module/__builtin__/test/test_abstractinst.py Thu Aug 7 19:02:00 2008
@@ -0,0 +1,182 @@
+from pypy.module.__builtin__.abstractinst import *
+
+
+class TestAbstractInst:
+
+ def test_abstract_isclass(self):
+ space = self.space
+ w_B1, w_B2, w_B3, w_X, w_Y = space.unpacktuple(space.appexec([], """():
+ class X(object): pass
+ class Y: pass
+ B1, B2, B3 = X(), X(), X()
+ B2.__bases__ = (42,)
+ B3.__bases__ = 'spam'
+ return B1, B2, B3, X, Y
+ """))
+ assert abstract_isclass_w(space, space.w_int) is True
+ assert abstract_isclass_w(space, w_B1) is False
+ assert abstract_isclass_w(space, w_B2) is True
+ assert abstract_isclass_w(space, w_B3) is False
+ assert abstract_isclass_w(space, w_X) is True
+ assert abstract_isclass_w(space, w_Y) is True
+
+ def test_abstract_getclass(self):
+ space = self.space
+ w_x, w_y, w_A, w_MyInst = space.unpacktuple(space.appexec([], """():
+ class MyInst(object):
+ def __init__(self, myclass):
+ self.myclass = myclass
+ def __class__(self):
+ if self.myclass is None:
+ raise AttributeError
+ return self.myclass
+ __class__ = property(__class__)
+ A = object()
+ x = MyInst(A)
+ y = MyInst(None)
+ return x, y, A, MyInst
+ """))
+ w_42 = space.wrap(42)
+ assert space.is_w(abstract_getclass(space, w_42), space.w_int)
+ assert space.is_w(abstract_getclass(space, w_x), w_A)
+ assert space.is_w(abstract_getclass(space, w_y), w_MyInst)
+ assert space.is_w(abstract_getclass(space, w_MyInst), space.w_type)
+
+
+class AppTestAbstractInst:
+
+ def test_abstract_isinstance(self):
+ class MyBaseInst(object):
+ pass
+ class MyInst(MyBaseInst):
+ def __init__(self, myclass):
+ self.myclass = myclass
+ def __class__(self):
+ if self.myclass is None:
+ raise AttributeError
+ return self.myclass
+ __class__ = property(__class__)
+ class MyInst2(MyBaseInst):
+ pass
+ class MyClass(object):
+ pass
+
+ A = MyClass()
+ x = MyInst(A)
+ assert x.__class__ is A
+ assert isinstance(x, MyInst)
+ assert isinstance(x, MyBaseInst)
+ assert not isinstance(x, MyInst2)
+ raises(TypeError, isinstance, x, A) # A has no __bases__
+ A.__bases__ = "hello world"
+ raises(TypeError, isinstance, x, A) # A.__bases__ is not tuple
+
+ class Foo(object):
+ pass
+ class SubFoo1(Foo):
+ pass
+ class SubFoo2(Foo):
+ pass
+ y = MyInst(SubFoo1)
+ assert isinstance(y, MyInst)
+ assert isinstance(y, MyBaseInst)
+ assert not isinstance(y, MyInst2)
+ assert isinstance(y, SubFoo1)
+ assert isinstance(y, Foo)
+ assert not isinstance(y, SubFoo2)
+
+ z = MyInst(None)
+ assert isinstance(z, MyInst)
+ assert isinstance(z, MyBaseInst)
+ assert not isinstance(z, MyInst2)
+ assert not isinstance(z, SubFoo1)
+
+ assert isinstance(y, ((), MyInst2, SubFoo1))
+ assert isinstance(y, (MyBaseInst, (SubFoo2,)))
+ assert not isinstance(y, (MyInst2, SubFoo2))
+ assert not isinstance(z, ())
+
+ class Foo(object):
+ pass
+ class Bar:
+ pass
+ u = MyInst(Foo)
+ assert isinstance(u, MyInst)
+ assert isinstance(u, MyBaseInst)
+ assert not isinstance(u, MyInst2)
+ assert isinstance(u, Foo)
+ assert not isinstance(u, Bar)
+ v = MyInst(Bar)
+ assert isinstance(v, MyInst)
+ assert isinstance(v, MyBaseInst)
+ assert not isinstance(v, MyInst2)
+ assert not isinstance(v, Foo)
+ assert isinstance(v, Bar)
+
+ BBase = MyClass()
+ BSub1 = MyClass()
+ BSub2 = MyClass()
+ BBase.__bases__ = ()
+ BSub1.__bases__ = (BBase,)
+ BSub2.__bases__ = (BBase,)
+ x = MyInst(BSub1)
+ assert isinstance(x, BSub1)
+ assert isinstance(x, BBase)
+ assert not isinstance(x, BSub2)
+ assert isinstance(x, (BSub2, (), (BSub1,)))
+
+ del BBase.__bases__
+ assert isinstance(x, BSub1)
+ raises(TypeError, isinstance, x, BBase)
+ assert not isinstance(x, BSub2)
+
+ BBase.__bases__ = "foobar"
+ assert isinstance(x, BSub1)
+ raises(TypeError, isinstance, x, BBase)
+ assert not isinstance(x, BSub2)
+
+ def test_abstract_issubclass(self):
+ class MyBaseInst(object):
+ pass
+ class MyInst(MyBaseInst):
+ pass
+ class MyInst2(MyBaseInst):
+ pass
+ class MyClass(object):
+ pass
+
+ assert issubclass(MyInst, MyBaseInst)
+ assert issubclass(MyInst2, MyBaseInst)
+ assert issubclass(MyBaseInst, MyBaseInst)
+ assert not issubclass(MyBaseInst, MyInst)
+ assert not issubclass(MyInst, MyInst2)
+
+ BBase = MyClass()
+ BSub1 = MyClass()
+ BSub2 = MyClass()
+ BBase.__bases__ = ()
+ BSub1.__bases__ = (BBase,)
+ BSub2.__bases__ = (BBase,)
+ assert issubclass(BSub1, BBase)
+ assert issubclass(BBase, BBase)
+ assert not issubclass(BBase, BSub1)
+ assert not issubclass(BSub1, BSub2)
+ assert not issubclass(MyInst, BSub1)
+ assert not issubclass(BSub1, MyInst)
+
+ del BBase.__bases__
+ raises(TypeError, issubclass, BSub1, BBase)
+ raises(TypeError, issubclass, BBase, BBase)
+ raises(TypeError, issubclass, BBase, BSub1)
+ assert not issubclass(BSub1, BSub2)
+ assert not issubclass(MyInst, BSub1)
+ assert not issubclass(BSub1, MyInst)
+
+ BBase.__bases__ = 42
+ raises(TypeError, issubclass, BSub1, BBase)
+ raises(TypeError, issubclass, BBase, BBase)
+ raises(TypeError, issubclass, BBase, BSub1)
+ assert not issubclass(BSub1, BSub2)
+ assert not issubclass(MyInst, BSub1)
+ assert not issubclass(BSub1, MyInst)
+
More information about the Pypy-commit
mailing list