Example #1
0
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))
Example #2
0
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
Example #3
0
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))
Example #4
0
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))