[pypy-svn] r75653 - in pypy/branch/fast-forward/pypy: interpreter objspace objspace/flow objspace/std objspace/test translator

benjamin at codespeak.net benjamin at codespeak.net
Mon Jun 28 22:12:22 CEST 2010


Author: benjamin
Date: Mon Jun 28 22:12:19 2010
New Revision: 75653

Modified:
   pypy/branch/fast-forward/pypy/interpreter/baseobjspace.py
   pypy/branch/fast-forward/pypy/objspace/descroperation.py
   pypy/branch/fast-forward/pypy/objspace/flow/operation.py
   pypy/branch/fast-forward/pypy/objspace/std/builtinshortcut.py
   pypy/branch/fast-forward/pypy/objspace/std/typeobject.py
   pypy/branch/fast-forward/pypy/objspace/test/test_descroperation.py
   pypy/branch/fast-forward/pypy/translator/geninterplevel.py
Log:
support __subclasscheck__ and __instancecheck__

Modified: pypy/branch/fast-forward/pypy/interpreter/baseobjspace.py
==============================================================================
--- pypy/branch/fast-forward/pypy/interpreter/baseobjspace.py	(original)
+++ pypy/branch/fast-forward/pypy/interpreter/baseobjspace.py	Mon Jun 28 22:12:19 2010
@@ -870,10 +870,6 @@
                 return self.w_True
         return self.w_False
 
-    def isinstance(self, w_obj, w_type):
-        w_objtype = self.type(w_obj)
-        return self.issubtype(w_objtype, w_type)
-
     def isinstance_w(self, w_obj, w_type):
         return self.is_true(self.isinstance(w_obj, w_type))
 
@@ -904,7 +900,7 @@
     # it with exception_
 
     def exception_is_valid_obj_as_class_w(self, w_obj):
-        if not self.is_true(self.isinstance(w_obj, self.w_type)):
+        if not self.isinstance_w(w_obj, self.w_type):
             return False
         if not self.full_exceptions:
             return True
@@ -1201,7 +1197,8 @@
     ('is_',             'is',        2, []),
     ('id',              'id',        1, []),
     ('type',            'type',      1, []),
-    ('issubtype',       'issubtype', 2, []),  # not for old-style classes
+    ('isinstance',      'isinstance', 2, ['__instancecheck__']),
+    ('issubtype',       'issubtype', 2, ['__subclasscheck__']),  # not for old-style classes
     ('repr',            'repr',      1, ['__repr__']),
     ('str',             'str',       1, ['__str__']),
     ('format',          'format',    2, ['__format__']),

Modified: pypy/branch/fast-forward/pypy/objspace/descroperation.py
==============================================================================
--- pypy/branch/fast-forward/pypy/objspace/descroperation.py	(original)
+++ pypy/branch/fast-forward/pypy/objspace/descroperation.py	Mon Jun 28 22:12:19 2010
@@ -464,10 +464,19 @@
             raise OperationError(space.w_TypeError,
                                  space.wrap("coercion should return None or 2-tuple"))
         return w_res
-    
 
+    def issubtype(space, w_sub, w_type):
+        w_check = space.lookup(w_type, "__subclasscheck__")
+        if w_check is None:
+            raise OperationError(space.w_TypeError,
+                                 space.wrap("issubclass not supported here"))
+        return space.get_and_call_function(w_check, w_type, w_sub)
 
-    # xxx ord
+    def isinstance(space, w_inst, w_type):
+        w_check = space.lookup(w_type, "__instancecheck__")
+        if w_check is not None:
+            return space.get_and_call_function(w_check, w_type, w_inst)
+        return space.issubtype(space.type(w_inst), w_type)
 
 
 

Modified: pypy/branch/fast-forward/pypy/objspace/flow/operation.py
==============================================================================
--- pypy/branch/fast-forward/pypy/objspace/flow/operation.py	(original)
+++ pypy/branch/fast-forward/pypy/objspace/flow/operation.py	Mon Jun 28 22:12:19 2010
@@ -174,6 +174,7 @@
     ('id',              id),
     ('type',            new_style_type),
     ('type',            type),
+    ('isinstance',      isinstance),
     ('issubtype',       issubclass),
     ('repr',            repr),
     ('str',             str),

Modified: pypy/branch/fast-forward/pypy/objspace/std/builtinshortcut.py
==============================================================================
--- pypy/branch/fast-forward/pypy/objspace/std/builtinshortcut.py	(original)
+++ pypy/branch/fast-forward/pypy/objspace/std/builtinshortcut.py	Mon Jun 28 22:12:19 2010
@@ -39,6 +39,7 @@
                  'abs', 'hex', 'oct',             # rare stuff?
                  'pos', 'divmod', 'cmp',          # rare stuff?
                  'float', 'long', 'coerce',       # rare stuff?
+                 'isinstance', 'issubtype',
                  ]
 # We cannot support {get,set,del}slice right now because
 # DescrOperation.{get,set,del}slice do a bit more work than just call

Modified: pypy/branch/fast-forward/pypy/objspace/std/typeobject.py
==============================================================================
--- pypy/branch/fast-forward/pypy/objspace/std/typeobject.py	(original)
+++ pypy/branch/fast-forward/pypy/objspace/std/typeobject.py	Mon Jun 28 22:12:19 2010
@@ -321,7 +321,7 @@
             raise operationerrfmt(space.w_TypeError,
                 "X is not a type object ('%s')",
                 space.type(w_subtype).getname(space, '?'))
-        if not space.is_true(space.issubtype(w_subtype, w_self)):
+        if not w_subtype.issubtype(w_self):
             raise operationerrfmt(space.w_TypeError,
                 "%s.__new__(%s): %s is not a subtype of %s",
                 w_self.name, w_subtype.name, w_subtype.name, w_self.name)
@@ -358,6 +358,17 @@
     def is_cpytype(w_self):
         return w_self.__flags__ & _CPYTYPE
 
+    def issubtype(w_self, w_type):
+        w_self = hint(w_self, promote=True)
+        w_type = hint(w_type, promote=True)
+        if w_self.space.config.objspace.std.withtypeversion and we_are_jitted():
+            version_tag1 = w_self.version_tag()
+            version_tag2 = w_type.version_tag()
+            if version_tag1 is not None and version_tag2 is not None:
+                res = _pure_issubtype(w_self, w_type, version_tag1, version_tag2)
+                return res
+        return _issubtype(w_self, w_type)
+
     def get_module(w_self):
         space = w_self.space
         if w_self.is_heaptype() and '__module__' in w_self.dict_w:
@@ -700,24 +711,18 @@
                                  space.wrap("__init__() should return None"))
     return w_newobject
 
-def _issubtype(w_type1, w_type2):
-    return w_type2 in w_type1.mro_w
+def _issubtype(w_sub, w_type):
+    return w_type in w_sub.mro_w
 
 @purefunction_promote()
-def _pure_issubtype(w_type1, w_type2, version_tag1, version_tag2):
-    return _issubtype(w_type1, w_type2)
+def _pure_issubtype(w_sub, w_type, version_tag1, version_tag2):
+    return _issubtype(w_sub, w_type)
+
+def issubtype__Type_Type(space, w_type, w_sub):
+    return space.newbool(w_sub.issubtype(w_type))
 
-def issubtype__Type_Type(space, w_type1, w_type2):
-    w_type1 = hint(w_type1, promote=True)
-    w_type2 = hint(w_type2, promote=True)
-    if space.config.objspace.std.withtypeversion and we_are_jitted():
-        version_tag1 = w_type1.version_tag()
-        version_tag2 = w_type2.version_tag()
-        if version_tag1 is not None and version_tag2 is not None:
-            res = _pure_issubtype(w_type1, w_type2, version_tag1, version_tag2)
-            return space.newbool(res)
-    res = _issubtype(w_type1, w_type2)
-    return space.newbool(res)
+def isinstance__Type_ANY(space, w_type, w_inst):
+    return space.newbool(space.type(w_inst).issubtype(w_type))
 
 def repr__Type(space, w_obj):
     w_mod = w_obj.get_module()

Modified: pypy/branch/fast-forward/pypy/objspace/test/test_descroperation.py
==============================================================================
--- pypy/branch/fast-forward/pypy/objspace/test/test_descroperation.py	(original)
+++ pypy/branch/fast-forward/pypy/objspace/test/test_descroperation.py	Mon Jun 28 22:12:19 2010
@@ -463,6 +463,33 @@
                 return self
         raises(TypeError, iter, x())
 
+    def test_isinstance_and_issubclass(self):
+        class Meta(type):
+            def __instancecheck__(cls, instance):
+                if cls is A:
+                    return True
+                return False
+            def __subclasscheck__(cls, sub):
+                if cls is B:
+                    return True
+                return False
+        class A:
+            __metaclass__ = Meta
+        class B(A):
+            pass
+        a = A()
+        b = B()
+        assert isinstance(a, A)
+        assert not isinstance(a, B)
+        assert isinstance(b, A)
+        assert not isinstance(b, B)
+        assert isinstance(4, A)
+        assert not issubclass(A, A)
+        assert not issubclass(B, A)
+        assert issubclass(A, B)
+        assert issubclass(B, B)
+        assert issubclass(23, B)
+
 
 class AppTestWithBuiltinShortcut(AppTest_Descroperation):
     OPTIONS = {'objspace.std.builtinshortcut': True}

Modified: pypy/branch/fast-forward/pypy/translator/geninterplevel.py
==============================================================================
--- pypy/branch/fast-forward/pypy/translator/geninterplevel.py	(original)
+++ pypy/branch/fast-forward/pypy/translator/geninterplevel.py	Mon Jun 28 22:12:19 2010
@@ -225,13 +225,14 @@
         return ", ".join(res)
 
     def oper(self, op, localscope):
-        if op.opname == 'issubtype':
+        if op.opname in ('issubtype', 'isinstance'):
             arg = op.args[1]
             if (not isinstance(arg, Constant)
                 or not isinstance(arg.value, (type, types.ClassType))):
-                  op = SpaceOperation("simple_call",
-                                      [Constant(issubclass)]+op.args,
-                                      op.result)
+                func = issubclass if op.opname == 'issubtype' else isinstance
+                op = SpaceOperation("simple_call",
+                                    [Constant(func)]+op.args,
+                                    op.result)
         if op.opname == "simple_call":
             v = op.args[0]
             space_shortcut = self.try_space_shortcut_for_builtin(v, len(op.args)-1,
@@ -703,21 +704,15 @@
             arities = self._space_arities = {}
             for name, sym, arity, specnames in self.space.MethodTable:
                 arities[name] = arity
-            arities['isinstance'] = 2
+            del arities["isinstance"]
         return self._space_arities
         
     def try_space_shortcut_for_builtin(self, v, nargs, args):
         if isinstance(v, Constant) and v.value in self.ibuiltin_ids:
             name = self.ibuiltin_ids[v.value].__name__
-            if hasattr(self.space, name):
-                if self.space_arities().get(name, -1) == nargs:
-                    if name != 'isinstance':
-                        return "space.%s" % name
-                    else:
-                        arg = args[1]
-                        if (isinstance(arg, Constant)
-                            and isinstance(arg.value, (type, types.ClassType))):
-                            return "space.isinstance"
+            if (hasattr(self.space, name) and
+                self.space_arities().get(name, -1) == nargs):
+                return "space.%s" % name
         return None
         
     def nameof_builtin_function_or_method(self, func):



More information about the Pypy-commit mailing list