def object_len(node, context=None): """Infer length of given node object :param Union[nodes.ClassDef, nodes.Instance] node: :param node: Node to infer length of :raises AstroidTypeError: If an invalid node is returned from __len__ method or no __len__ method exists :raises InferenceError: If the given node cannot be inferred or if multiple nodes are inferred :rtype int: Integer length of node """ # pylint: disable=import-outside-toplevel; circular import from astroid.objects import FrozenSet inferred_node = safe_infer(node, context=context) if inferred_node is None or inferred_node is util.Uninferable: raise exceptions.InferenceError(node=node) if isinstance(inferred_node, nodes.Const) and isinstance( inferred_node.value, (bytes, str)): return len(inferred_node.value) if isinstance(inferred_node, (nodes.List, nodes.Set, nodes.Tuple, FrozenSet)): return len(inferred_node.elts) if isinstance(inferred_node, nodes.Dict): return len(inferred_node.items) node_type = object_type(inferred_node, context=context) if not node_type: raise exceptions.InferenceError(node=node) try: len_call = next(node_type.igetattr("__len__", context=context)) except exceptions.AttributeInferenceError: raise exceptions.AstroidTypeError( "object of type '{}' has no len()".format(node_type.pytype())) result_of_len = next(len_call.infer_call_result(node, context)) if (isinstance(result_of_len, nodes.Const) and result_of_len.pytype() == "builtins.int"): return result_of_len.value if isinstance( result_of_len, bases.Instance) and result_of_len.is_subtype_of("builtins.int"): # Fake a result as we don't know the arguments of the instance call. return 0 raise exceptions.AstroidTypeError( "'{}' object cannot be interpreted as an integer".format( result_of_len))
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 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 issubclass # issubclass(type, (object, 1)) evaluates to true # issubclass(object, (1, type)) raises TypeError for klass in class_seq: if klass is util.Uninferable: 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_len(node, context=None): """Infer length of given node object :param Union[nodes.ClassDef, nodes.Instance] node: :param node: Node to infer length of :raises AstroidTypeError: If an invalid node is returned from __len__ method or no __len__ method exists :raises InferenceError: If the given node cannot be inferred or if multiple nodes are inferred :rtype int: Integer length of node """ from astroid.objects import FrozenSet inferred_node = safe_infer(node, context=context) if inferred_node is None or inferred_node is util.Uninferable: raise exceptions.InferenceError(node=node) if (isinstance(inferred_node, nodes.Const) and isinstance(inferred_node.value, (bytes, str))): return len(inferred_node.value) if isinstance(inferred_node, (nodes.List, nodes.Set, nodes.Tuple, FrozenSet)): return len(inferred_node.elts) if isinstance(inferred_node, nodes.Dict): return len(inferred_node.items) try: node_type = object_type(inferred_node, context=context) len_call = next(node_type.igetattr("__len__", context=context)) except exceptions.AttributeInferenceError: raise exceptions.AstroidTypeError( "object of type '{}' has no len()".format(len_call.pytype())) try: result_of_len = next(len_call.infer_call_result(node, context)) # Remove StopIteration catch when #507 is fixed except StopIteration: raise exceptions.InferenceError(node=node) if (isinstance(result_of_len, nodes.Const) and result_of_len.pytype() == "builtins.int"): return result_of_len.value else: raise exceptions.AstroidTypeError( "'{}' object cannot be interpreted as an integer".format( result_of_len))
def object_len(node, context=None): """Infer length of given node object :param Union[nodes.ClassDef, nodes.Instance] node: :param node: Node to infer length of :raises AstroidTypeError: If an invalid node is returned from __len__ method or no __len__ method exists :raises InferenceError: If the given node cannot be inferred or if multiple nodes are inferred or if the code executed in python would result in a infinite recursive check for length :rtype int: Integer length of node """ # pylint: disable=import-outside-toplevel; circular import from astroid.objects import FrozenSet inferred_node = safe_infer(node, context=context) # prevent self referential length calls from causing a recursion error # see https://github.com/PyCQA/astroid/issues/777 node_frame = node.frame() if (isinstance(node_frame, scoped_nodes.FunctionDef) and node_frame.name == "__len__" and inferred_node is not None and inferred_node._proxied == node_frame.parent): message = ("Self referential __len__ function will " "cause a RecursionError on line {} of {}".format( node.lineno, node.root().file)) raise exceptions.InferenceError(message) if inferred_node is None or inferred_node is util.Uninferable: raise exceptions.InferenceError(node=node) if isinstance(inferred_node, nodes.Const) and isinstance( inferred_node.value, (bytes, str)): return len(inferred_node.value) if isinstance(inferred_node, (nodes.List, nodes.Set, nodes.Tuple, FrozenSet)): return len(inferred_node.elts) if isinstance(inferred_node, nodes.Dict): return len(inferred_node.items) node_type = object_type(inferred_node, context=context) if not node_type: raise exceptions.InferenceError(node=node) try: len_call = next(node_type.igetattr("__len__", context=context)) except exceptions.AttributeInferenceError as e: raise exceptions.AstroidTypeError( "object of type '{}' has no len()".format( node_type.pytype())) from e result_of_len = next(len_call.infer_call_result(node, context)) if (isinstance(result_of_len, nodes.Const) and result_of_len.pytype() == "builtins.int"): return result_of_len.value if isinstance( result_of_len, bases.Instance) and result_of_len.is_subtype_of("builtins.int"): # Fake a result as we don't know the arguments of the instance call. return 0 raise exceptions.AstroidTypeError( "'{}' object cannot be interpreted as an integer".format( result_of_len))