Skip to content
Snippets Groups Projects
Commit 47cee57f authored by Claudiu Popa's avatar Claudiu Popa
Browse files

Rewrite the object_isinstance and object_issubclass helpers to rely on common code

parent 46788811
No related branches found
No related tags found
No related merge requests found
Loading
Loading
@@ -83,39 +83,46 @@ def object_type(node, context=None):
return list(types)[0]
 
 
def object_isinstance(node, class_or_seq, context=None):
"""Check if a node 'isinstance' any node in class_or_seq
:param node: A given node
:param class_or_seq: Union[Nodes.NodeNG], Sequence[nodes.NodeNG]]
:rtype: bool
:raises AstroidTypeError: if the given ``classes_or_seq`` are not types
"""
def _object_type_is_subclass(obj_type, class_or_seq, context=None):
if not isinstance(class_or_seq, (tuple, list)):
class_seq = (class_or_seq,)
else:
class_seq = class_or_seq
obj_type = object_type(node, context)
if obj_type is util.Uninferable:
return util.Uninferable
 
# Instances are not types
class_seq = [item if not isinstance(item, bases.Instance)
else util.Uninferable for item in class_seq]
# strict compatibility with isinstance
# isinstance(1, (int, 1)) evaluates to true
# isinstance(1, (1, int)) raises TypeError
# strict compatibility with issubclass
# issubclass(1, (int, 1)) evaluates to true
# issubclass(1, (1, int)) raises TypeError
for klass in class_seq:
if klass is util.Uninferable:
raise exceptions.AstroidTypeError(
"isinstance() arg 2 must be a type or tuple of types")
raise exceptions.AstroidTypeError("arg 2 must be a type or tuple of types")
for obj_subclass in obj_type.mro():
if obj_subclass == klass:
return True
return False
 
 
def object_isinstance(node, class_or_seq, context=None):
"""Check if a node 'isinstance' any node in class_or_seq
:param node: A given node
:param class_or_seq: Union[Nodes.NodeNG], Sequence[nodes.NodeNG]]
:rtype: bool
:raises AstroidTypeError: if the given ``classes_or_seq`` are not types
"""
obj_type = object_type(node, context)
if obj_type is util.Uninferable:
return util.Uninferable
return _object_type_is_subclass(obj_type, class_or_seq, context=context)
def object_issubclass(node, class_or_seq, context=None):
"""Check if a type is a subclass of any node in class_or_seq
 
Loading
Loading
@@ -127,28 +134,9 @@ def object_issubclass(node, class_or_seq, context=None):
:raises AstroidError: if the type of the given node cannot be inferred
or its type's mro doesn't work
"""
if not isinstance(class_or_seq, (tuple, list)):
class_seq = (class_or_seq,)
else:
class_seq = class_or_seq
if not isinstance(node, nodes.ClassDef):
raise TypeError("{node} needs to be a ClassDef node".format(node=node))
# Instances are not types
class_seq = [item if not isinstance(item, bases.Instance)
else util.Uninferable for item in class_seq]
# strict compatibility with issubclass
# issubclass(int, (int, 1)) evaluates to true
# issubclass(int, (1, int)) raises TypeError
for klass in class_seq:
if klass is util.Uninferable:
raise exceptions.AstroidTypeError(
"issubclass() arg 2 must be a type or tuple of types")
for obj_subclass in node.mro():
if obj_subclass == klass:
return True
return False
return _object_type_is_subclass(node, class_or_seq, context=context)
 
 
def safe_infer(node, context=None):
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment