[pypy-commit] pypy issue2343: Copy CPython's logic more closely

arigo pypy.commits at gmail.com
Thu Jul 14 10:52:51 EDT 2016


Author: Armin Rigo <arigo at tunes.org>
Branch: issue2343
Changeset: r85695:66c0e2134605
Date: 2016-07-14 16:54 +0200
http://bitbucket.org/pypy/pypy/changeset/66c0e2134605/

Log:	Copy CPython's logic more closely

diff --git a/pypy/module/__builtin__/abstractinst.py b/pypy/module/__builtin__/abstractinst.py
--- a/pypy/module/__builtin__/abstractinst.py
+++ b/pypy/module/__builtin__/abstractinst.py
@@ -46,72 +46,34 @@
             raise       # propagate other errors
         return space.type(w_obj)
 
- at jit.unroll_safe
-def abstract_isinstance_w(space, w_obj, w_klass_or_tuple, allow_override=False):
-    """Implementation for the full 'isinstance(obj, klass_or_tuple)'."""
-    # -- case (anything, tuple)
-    # XXX it might be risky that the JIT sees this
-    if space.isinstance_w(w_klass_or_tuple, space.w_tuple):
-        for w_klass in space.fixedview(w_klass_or_tuple):
-            if abstract_isinstance_w(space, w_obj, w_klass, allow_override):
-                return True
-        return False
 
-    # -- case (anything, type)
+# ---------- isinstance ----------
+
+
+def p_recursive_isinstance_w(space, w_inst, w_cls):
+    # Copied straight from CPython 2.7.  Does not handle 'cls' being a tuple.
+    if (isinstance(w_cls, W_ClassObject) and
+        isinstance(w_inst, W_InstanceObject)):
+        return w_inst.w_class.is_subclass_of(w_cls)
+
+    if space.isinstance_w(w_cls, space.w_type):
+        return p_recursive_isinstance_type_w(space, w_inst, w_cls)
+
+    check_class(space, w_cls, "isinstance() arg 2 must be a class, type,"
+                              " or tuple of classes and types")
     try:
-        if allow_override:
-            w_result = space.isinstance_allow_override(w_obj, w_klass_or_tuple)
-        else:
-            w_result = space.isinstance(w_obj, w_klass_or_tuple)
-    except OperationError as 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)
-            if not allow_override:
-                return space.issubtype_w(w_pretendtype, w_klass_or_tuple)
-            w_result = space.issubtype_allow_override(w_pretendtype,
-                                                      w_klass_or_tuple)
-        except OperationError as 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)
-    if isinstance(w_klass_or_tuple, W_ClassObject):
-        if isinstance(w_obj, W_InstanceObject):
-            return w_obj.w_class.is_subclass_of(w_klass_or_tuple)
-    return _abstract_isinstance_w_helper(space, w_obj, w_klass_or_tuple)
-
-
-def _abstract_isinstance_w_helper(space, w_obj, w_klass_or_tuple):
-    # -- 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__'))
+        w_abstractclass = space.getattr(w_inst, space.wrap('__class__'))
     except OperationError as e:
         if e.async(space):      # ignore most exceptions
             raise
         return False
     else:
-        return _issubclass_recurse(space, w_abstractclass, w_klass_or_tuple)
+        return p_abstract_issubclass_w(space, w_abstractclass, w_cls)
 
 
-def recursive_isinstance_type_w(space, w_inst, w_type):
-    # subfunctionality of recursive_isinstance(): assumes that w_type is
-    # a type object.
+def p_recursive_isinstance_type_w(space, w_inst, w_type):
+    # subfunctionality of p_recursive_isinstance_w(): assumes that w_type is
+    # a type object.  Copied straight from CPython 2.7.
     if space.isinstance_w(w_inst, w_type):
         return True
     try:
@@ -126,9 +88,73 @@
     return False
 
 
-def recursive_issubclass_w(space, w_derived, w_cls):
-    # From CPython's function of the same name, which as far as I can tell
-    # is not recursive.
+ at jit.unroll_safe
+def abstract_isinstance_w(space, w_obj, w_klass_or_tuple, allow_override=False):
+    """Implementation for the full 'isinstance(obj, klass_or_tuple)'."""
+    # Copied from CPython 2.7's PyObject_Isinstance().  Additionally,
+    # if 'allow_override' is False (the default), then don't try to
+    # use a custom __instancecheck__ method.
+
+    # WARNING: backward compatibility function name here.  CPython
+    # uses the name "abstract" to refer to the logic of handling
+    # class-like objects, with a "__bases__" attribute.  This function
+    # here is not related to that and implements the full
+    # PyObject_IsInstance() logic.
+
+    # Quick test for an exact match
+    if space.type(w_obj) is w_klass_or_tuple:
+        return True
+
+    # -- case (anything, tuple)
+    # XXX it might be risky that the JIT sees this
+    if space.isinstance_w(w_klass_or_tuple, space.w_tuple):
+        for w_klass in space.fixedview(w_klass_or_tuple):
+            if abstract_isinstance_w(space, w_obj, w_klass, allow_override):
+                return True
+        return False
+
+    # -- case (anything, type)
+    if allow_override:
+        w_check = space.lookup(w_klass_or_tuple, "__instancecheck__")
+        if w_check is not None:
+            # this is the common case: all type objects have a method
+            # __instancecheck__.  The one in the base 'type' type calls
+            # back p_recursive_isinstance_type_w() from the present module.
+            return space.is_true(space.get_and_call_function(
+                w_check, w_klass_or_tuple, w_obj))
+
+    return p_recursive_isinstance_w(space, w_obj, w_klass_or_tuple)
+
+
+# ---------- issubclass ----------
+
+
+ at jit.unroll_safe
+def p_abstract_issubclass_w(space, w_derived, w_cls):
+    # Copied straight from CPython 2.7, function abstract_issubclass().
+    # Don't confuse this with the function abstract_issubclass_w() below.
+    # Here, w_cls cannot be a tuple.
+    while True:
+        if space.is_w(w_derived, w_cls):
+            return True
+        w_bases = _get_bases(space, w_derived)
+        if w_bases is None:
+            return False
+        bases_w = space.fixedview(w_bases)
+        last_index = len(bases_w) - 1
+        if last_index < 0:
+            return False
+        # Avoid recursivity in the single inheritance case; in general,
+        # don't recurse on the last item in the tuple (loop instead).
+        for i in range(last_index):
+            if p_abstract_issubclass_w(space, bases_w[i], w_cls):
+                return True
+        w_derived = bases_w[last_index]
+
+
+def p_recursive_issubclass_w(space, w_derived, w_cls):
+    # From CPython's function of the same name (which as far as I can tell
+    # is not recursive).  Copied straight from CPython 2.7.
     if (space.isinstance_w(w_cls, space.w_type) and
         space.isinstance_w(w_derived, space.w_type)):
         return space.issubtype_w(w_derived, w_cls)
@@ -140,21 +166,7 @@
     check_class(space, w_derived, "issubclass() arg 1 must be a class")
     check_class(space, w_cls, "issubclass() arg 2 must be a class"
                               " or tuple of classes")
-    XXXX
-    return abstract_issubclass_w(space, w_derived, w_cls)
-
-
- at jit.unroll_safe
-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.fixedview(w_bases):
-            if _issubclass_recurse(space, w_base, w_top):
-                return True
-    return False
+    return p_abstract_issubclass_w(space, w_derived, w_cls)
 
 
 @jit.unroll_safe
@@ -162,37 +174,31 @@
                           allow_override=False):
     """Implementation for the full 'issubclass(derived, klass_or_tuple)'."""
 
-    # -- case (class-like-object, tuple-of-classes)
+    # WARNING: backward compatibility function name here.  CPython
+    # uses the name "abstract" to refer to the logic of handling
+    # class-like objects, with a "__bases__" attribute.  This function
+    # here is not related to that and implements the full
+    # PyObject_IsSubclass() logic.  There is also p_abstract_issubclass_w().
+
+    # -- case (anything, tuple-of-classes)
     if space.isinstance_w(w_klass_or_tuple, space.w_tuple):
         for w_klass in space.fixedview(w_klass_or_tuple):
             if abstract_issubclass_w(space, w_derived, w_klass, allow_override):
                 return True
         return False
 
-    # -- case (type, type)
-    try:
-        if not allow_override:
-            return space.issubtype_w(w_derived, w_klass_or_tuple)
-        w_result = space.issubtype_allow_override(w_derived, w_klass_or_tuple)
-    except OperationError as 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 (anything, type)
+    if allow_override:
+        w_check = space.lookup(w_klass_or_tuple, "__subclasscheck__")
+        if w_check is not None:
+            # this is the common case: all type objects have a method
+            # __subclasscheck__.  The one in the base 'type' type calls
+            # back p_recursive_issubclass_w() from the present module.
+            return space.is_true(space.get_and_call_function(
+                w_check, w_klass_or_tuple, w_derived))
 
-    # -- case (old-style class, old-style class)
-    if isinstance(w_derived, W_ClassObject):
-        if isinstance(w_klass_or_tuple, W_ClassObject):
-            return w_derived.is_subclass_of(w_klass_or_tuple)
-    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
+    return p_recursive_issubclass_w(space, w_derived, w_klass_or_tuple)
 
-    # -- 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)
 
 # ------------------------------------------------------------
 # Exception helpers
diff --git a/pypy/objspace/descroperation.py b/pypy/objspace/descroperation.py
--- a/pypy/objspace/descroperation.py
+++ b/pypy/objspace/descroperation.py
@@ -509,21 +509,6 @@
     def isinstance(space, w_inst, w_type):
         return space.wrap(space.isinstance_w(w_inst, w_type))
 
-    def issubtype_allow_override(space, w_sub, w_type):
-        w_check = space.lookup(w_type, "__subclasscheck__")
-        if w_check is None:
-            raise oefmt(space.w_TypeError, "issubclass not supported here")
-        return space.get_and_call_function(w_check, w_type, w_sub)
-
-    def isinstance_allow_override(space, w_inst, w_type):
-        if space.type(w_inst) is w_type:
-            return space.w_True # fast path copied from cpython
-        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)
-        else:
-            return space.isinstance(w_inst, w_type)
-
 
 # helpers
 
diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py
--- a/pypy/objspace/std/typeobject.py
+++ b/pypy/objspace/std/typeobject.py
@@ -903,12 +903,12 @@
 @gateway.unwrap_spec(w_obj=W_TypeObject)
 def type_issubtype(w_obj, space, w_sub):
     return space.newbool(
-        abstractinst.recursive_issubclass_w(space, w_sub, w_obj))
+        abstractinst.p_recursive_issubclass_w(space, w_sub, w_obj))
 
 @gateway.unwrap_spec(w_obj=W_TypeObject)
 def type_isinstance(w_obj, space, w_inst):
     return space.newbool(
-        abstractinst.recursive_isinstance_type_w(space, w_inst, w_obj))
+        abstractinst.p_recursive_isinstance_type_w(space, w_inst, w_obj))
 
 W_TypeObject.typedef = TypeDef("type",
     __new__ = gateway.interp2app(descr__new__),


More information about the pypy-commit mailing list