diff options
Diffstat (limited to 'astroid/helpers.py')
-rw-r--r-- | astroid/helpers.py | 35 |
1 files changed, 35 insertions, 0 deletions
diff --git a/astroid/helpers.py b/astroid/helpers.py index d3522442..bce1a59f 100644 --- a/astroid/helpers.py +++ b/astroid/helpers.py @@ -116,6 +116,41 @@ def object_isinstance(node, class_or_seq, context=None): return False +def object_issubclass(node, class_or_seq, context=None): + """Check if a type is a subclass of 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 + :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 + + def safe_infer(node, context=None): """Return the inferred value for the given node. |