[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