Пример #1
0
def _get_elts(arg, context):
    def is_iterable(n):
        return isinstance(n, (nodes.List, nodes.Tuple, nodes.Set))

    try:
        inferred = next(arg.infer(context))
    except (InferenceError, StopIteration) as exc:
        raise UseInferenceDefault from exc
    if isinstance(inferred, nodes.Dict):
        items = inferred.items
    elif is_iterable(inferred):
        items = []
        for elt in inferred.elts:
            # If an item is not a pair of two items,
            # then fallback to the default inference.
            # Also, take in consideration only hashable items,
            # tuples and consts. We are choosing Names as well.
            if not is_iterable(elt):
                raise UseInferenceDefault()
            if len(elt.elts) != 2:
                raise UseInferenceDefault()
            if not isinstance(elt.elts[0],
                              (nodes.Tuple, nodes.Const, nodes.Name)):
                raise UseInferenceDefault()
            items.append(tuple(elt.elts))
    else:
        raise UseInferenceDefault()
    return items
Пример #2
0
def infer_int(node, context=None):
    """Infer int() calls

    :param nodes.Call node: int() call to infer
    :param context.InferenceContext: node context
    :rtype nodes.Const: a Const containing the integer value of the int() call
    """
    call = arguments.CallSite.from_call(node, context=context)
    if call.keyword_arguments:
        raise UseInferenceDefault(
            "TypeError: int() must take no keyword arguments")

    if call.positional_arguments:
        try:
            first_value = next(
                call.positional_arguments[0].infer(context=context))
        except (InferenceError, StopIteration) as exc:
            raise UseInferenceDefault(str(exc)) from exc

        if first_value is util.Uninferable:
            raise UseInferenceDefault

        if isinstance(first_value, nodes.Const) and isinstance(
                first_value.value, (int, str)):
            try:
                actual_value = int(first_value.value)
            except ValueError:
                return nodes.Const(0)
            return nodes.Const(actual_value)

    return nodes.Const(0)
Пример #3
0
def infer_named_tuple(node, context=None):
    """Specific inference function for namedtuple Call node"""
    tuple_base_name = nodes.Name(name="tuple", parent=node.root())
    class_node, name, attributes = infer_func_form(
        node, tuple_base_name, context=context
    )
    call_site = arguments.CallSite.from_call(node, context=context)
    node = extract_node("import collections; collections.namedtuple")
    try:

        func = next(node.infer())
    except StopIteration as e:
        raise InferenceError(node=node) from e
    try:
        rename = next(call_site.infer_argument(func, "rename", context)).bool_value()
    except (InferenceError, StopIteration):
        rename = False

    try:
        attributes = _check_namedtuple_attributes(name, attributes, rename)
    except AstroidTypeError as exc:
        raise UseInferenceDefault("TypeError: " + str(exc)) from exc
    except AstroidValueError as exc:
        raise UseInferenceDefault("ValueError: " + str(exc)) from exc

    replace_args = ", ".join(f"{arg}=None" for arg in attributes)
    field_def = (
        "    {name} = property(lambda self: self[{index:d}], "
        "doc='Alias for field number {index:d}')"
    )
    field_defs = "\n".join(
        field_def.format(name=name, index=index)
        for index, name in enumerate(attributes)
    )
    fake = AstroidBuilder(AstroidManager()).string_build(
        f"""
class {name}(tuple):
    __slots__ = ()
    _fields = {attributes!r}
    def _asdict(self):
        return self.__dict__
    @classmethod
    def _make(cls, iterable, new=tuple.__new__, len=len):
        return new(cls, iterable)
    def _replace(self, {replace_args}):
        return self
    def __getnewargs__(self):
        return tuple(self)
{field_defs}
    """
    )
    class_node.locals["_asdict"] = fake.body[0].locals["_asdict"]
    class_node.locals["_make"] = fake.body[0].locals["_make"]
    class_node.locals["_replace"] = fake.body[0].locals["_replace"]
    class_node.locals["_fields"] = fake.body[0].locals["_fields"]
    for attr in attributes:
        class_node.locals[attr] = fake.body[0].locals[attr]
    # we use UseInferenceDefault, we can't be a generator so return an iterator
    return iter([class_node])
Пример #4
0
def _functools_partial_inference(
    node: nodes.Call,
    context: InferenceContext | None = None
) -> Iterator[objects.PartialFunction]:
    call = arguments.CallSite.from_call(node, context=context)
    number_of_positional = len(call.positional_arguments)
    if number_of_positional < 1:
        raise UseInferenceDefault(
            "functools.partial takes at least one argument")
    if number_of_positional == 1 and not call.keyword_arguments:
        raise UseInferenceDefault(
            "functools.partial needs at least to have some filled arguments")

    partial_function = call.positional_arguments[0]
    try:
        inferred_wrapped_function = next(
            partial_function.infer(context=context))
    except (InferenceError, StopIteration) as exc:
        raise UseInferenceDefault from exc
    if inferred_wrapped_function is Uninferable:
        raise UseInferenceDefault("Cannot infer the wrapped function")
    if not isinstance(inferred_wrapped_function, FunctionDef):
        raise UseInferenceDefault("The wrapped function is not a function")

    # Determine if the passed keywords into the callsite are supported
    # by the wrapped function.
    if not inferred_wrapped_function.args:
        function_parameters = []
    else:
        function_parameters = chain(
            inferred_wrapped_function.args.args or (),
            inferred_wrapped_function.args.posonlyargs or (),
            inferred_wrapped_function.args.kwonlyargs or (),
        )
    parameter_names = {
        param.name
        for param in function_parameters if isinstance(param, AssignName)
    }
    if set(call.keyword_arguments) - parameter_names:
        raise UseInferenceDefault(
            "wrapped function received unknown parameters")

    partial_function = objects.PartialFunction(
        call,
        name=inferred_wrapped_function.name,
        lineno=inferred_wrapped_function.lineno,
        col_offset=inferred_wrapped_function.col_offset,
        parent=node.parent,
    )
    partial_function.postinit(
        args=inferred_wrapped_function.args,
        body=inferred_wrapped_function.body,
        decorators=inferred_wrapped_function.decorators,
        returns=inferred_wrapped_function.returns,
        type_comment_returns=inferred_wrapped_function.type_comment_returns,
        type_comment_args=inferred_wrapped_function.type_comment_args,
        doc_node=inferred_wrapped_function.doc_node,
    )
    return iter((partial_function, ))
Пример #5
0
def infer_str(node, context=None):
    """Infer str() calls

    :param nodes.Call node: str() call to infer
    :param context.InferenceContext: node context
    :rtype nodes.Const: a Const containing an empty string
    """
    call = arguments.CallSite.from_call(node, context=context)
    if call.keyword_arguments:
        raise UseInferenceDefault("TypeError: str() must take no keyword arguments")
    try:
        return nodes.Const("")
    except (AstroidTypeError, InferenceError) as exc:
        raise UseInferenceDefault(str(exc)) from exc
Пример #6
0
def _container_generic_transform(  # pylint: disable=inconsistent-return-statements
        arg, context, klass, iterables, build_elts):
    if isinstance(arg, klass):
        return arg
    if isinstance(arg, iterables):
        if all(isinstance(elt, nodes.Const) for elt in arg.elts):
            elts = [elt.value for elt in arg.elts]
        else:
            # TODO: Does not handle deduplication for sets.
            elts = []
            for element in arg.elts:
                if not element:
                    continue
                inferred = helpers.safe_infer(element, context=context)
                if inferred:
                    evaluated_object = nodes.EvaluatedObject(original=element,
                                                             value=inferred)
                    elts.append(evaluated_object)
    elif isinstance(arg, nodes.Dict):
        # Dicts need to have consts as strings already.
        if not all(isinstance(elt[0], nodes.Const) for elt in arg.items):
            raise UseInferenceDefault()
        elts = [item[0].value for item in arg.items]
    elif isinstance(arg, nodes.Const) and isinstance(arg.value, (str, bytes)):
        elts = arg.value
    else:
        return
    return klass.from_elements(elts=build_elts(elts))
Пример #7
0
def _infer_first(node, context):
    if node is util.Uninferable:
        raise UseInferenceDefault
    try:
        value = next(node.infer(context=context))
    except StopIteration as exc:
        raise InferenceError from exc
    if value is util.Uninferable:
        raise UseInferenceDefault()
    return value
Пример #8
0
def infer_issubclass(callnode, context=None):
    """Infer issubclass() calls

    :param nodes.Call callnode: an `issubclass` call
    :param InferenceContext context: the context for the inference
    :rtype nodes.Const: Boolean Const value of the `issubclass` call
    :raises UseInferenceDefault: If the node cannot be inferred
    """
    call = arguments.CallSite.from_call(callnode, context=context)
    if call.keyword_arguments:
        # issubclass doesn't support keyword arguments
        raise UseInferenceDefault("TypeError: issubclass() takes no keyword arguments")
    if len(call.positional_arguments) != 2:
        raise UseInferenceDefault(
            "Expected two arguments, got {count}".format(
                count=len(call.positional_arguments)
            )
        )
    # The left hand argument is the obj to be checked
    obj_node, class_or_tuple_node = call.positional_arguments

    try:
        obj_type = next(obj_node.infer(context=context))
    except (InferenceError, StopIteration) as exc:
        raise UseInferenceDefault from exc
    if not isinstance(obj_type, nodes.ClassDef):
        raise UseInferenceDefault("TypeError: arg 1 must be class")

    # The right hand argument is the class(es) that the given
    # object is to be checked against.
    try:
        class_container = _class_or_tuple_to_container(
            class_or_tuple_node, context=context
        )
    except InferenceError as exc:
        raise UseInferenceDefault from exc
    try:
        issubclass_bool = helpers.object_issubclass(obj_type, class_container, context)
    except AstroidTypeError as exc:
        raise UseInferenceDefault("TypeError: " + str(exc)) from exc
    except MroError as exc:
        raise UseInferenceDefault from exc
    return nodes.Const(issubclass_bool)
Пример #9
0
def infer_len(node, context=None):
    """Infer length calls

    :param nodes.Call node: len call to infer
    :param context.InferenceContext: node context
    :rtype nodes.Const: a Const node with the inferred length, if possible
    """
    call = arguments.CallSite.from_call(node, context=context)
    if call.keyword_arguments:
        raise UseInferenceDefault(
            "TypeError: len() must take no keyword arguments")
    if len(call.positional_arguments) != 1:
        raise UseInferenceDefault(
            "TypeError: len() must take exactly one argument "
            "({len}) given".format(len=len(call.positional_arguments)))
    [argument_node] = call.positional_arguments

    try:
        return nodes.Const(helpers.object_len(argument_node, context=context))
    except (AstroidTypeError, InferenceError) as exc:
        raise UseInferenceDefault(str(exc)) from exc
Пример #10
0
def infer_isinstance(callnode, context=None):
    """Infer isinstance calls

    :param nodes.Call callnode: an isinstance call
    :param InferenceContext context: context for call
        (currently unused but is a common interface for inference)
    :rtype nodes.Const: Boolean Const value of isinstance call

    :raises UseInferenceDefault: If the node cannot be inferred
    """
    call = arguments.CallSite.from_call(callnode, context=context)
    if call.keyword_arguments:
        # isinstance doesn't support keyword arguments
        raise UseInferenceDefault("TypeError: isinstance() takes no keyword arguments")
    if len(call.positional_arguments) != 2:
        raise UseInferenceDefault(
            "Expected two arguments, got {count}".format(
                count=len(call.positional_arguments)
            )
        )
    # The left hand argument is the obj to be checked
    obj_node, class_or_tuple_node = call.positional_arguments
    # The right hand argument is the class(es) that the given
    # obj is to be check is an instance of
    try:
        class_container = _class_or_tuple_to_container(
            class_or_tuple_node, context=context
        )
    except InferenceError as exc:
        raise UseInferenceDefault from exc
    try:
        isinstance_bool = helpers.object_isinstance(obj_node, class_container, context)
    except AstroidTypeError as exc:
        raise UseInferenceDefault("TypeError: " + str(exc)) from exc
    except MroError as exc:
        raise UseInferenceDefault from exc
    if isinstance_bool is util.Uninferable:
        raise UseInferenceDefault
    return nodes.Const(isinstance_bool)
Пример #11
0
def _infer_copy_method(
        node: nodes.Call,
        context: InferenceContext | None = None) -> Iterator[nodes.NodeNG]:
    assert isinstance(node.func, nodes.Attribute)
    inferred_orig, inferred_copy = itertools.tee(
        node.func.expr.infer(context=context))
    if all(
            isinstance(inferred_node, (nodes.Dict, nodes.List, nodes.Set,
                                       objects.FrozenSet))
            for inferred_node in inferred_orig):
        return inferred_copy

    raise UseInferenceDefault()
Пример #12
0
def infer_namespace(node, context=None):
    callsite = arguments.CallSite.from_call(node, context=context)
    if not callsite.keyword_arguments:
        # Cannot make sense of it.
        raise UseInferenceDefault()

    class_node = nodes.ClassDef("Namespace", "docstring")
    class_node.parent = node.parent
    for attr in set(callsite.keyword_arguments):
        fake_node = nodes.EmptyNode()
        fake_node.parent = class_node
        fake_node.attrname = attr
        class_node.instance_attrs[attr] = [fake_node]
    return iter((class_node.instantiate_class(),))
Пример #13
0
def _inference_tip_cached(func: InferFn, instance: None, args: typing.Any,
                          kwargs: typing.Any) -> Iterator[InferOptions]:
    """Cache decorator used for inference tips"""
    node = args[0]
    try:
        result = _cache[func, node]
        # If through recursion we end up trying to infer the same
        # func + node we raise here.
        if result is None:
            raise UseInferenceDefault()
    except KeyError:
        _cache[func, node] = None
        result = _cache[func, node] = list(func(*args, **kwargs))
        assert result
    return iter(result)
Пример #14
0
def _container_generic_inference(node, context, node_type, transform):
    args = node.args
    if not args:
        return node_type()
    if len(node.args) > 1:
        raise UseInferenceDefault()

    (arg, ) = args
    transformed = transform(arg)
    if not transformed:
        try:
            inferred = next(arg.infer(context=context))
        except (InferenceError, StopIteration) as exc:
            raise UseInferenceDefault from exc
        if inferred is util.Uninferable:
            raise UseInferenceDefault
        transformed = transform(inferred)
    if not transformed or transformed is util.Uninferable:
        raise UseInferenceDefault
    return transformed
Пример #15
0
def infer_dict(node, context=None):
    """Try to infer a dict call to a Dict node.

    The function treats the following cases:

        * dict()
        * dict(mapping)
        * dict(iterable)
        * dict(iterable, **kwargs)
        * dict(mapping, **kwargs)
        * dict(**kwargs)

    If a case can't be inferred, we'll fallback to default inference.
    """
    call = arguments.CallSite.from_call(node, context=context)
    if call.has_invalid_arguments() or call.has_invalid_keywords():
        raise UseInferenceDefault

    args = call.positional_arguments
    kwargs = list(call.keyword_arguments.items())

    if not args and not kwargs:
        # dict()
        return nodes.Dict()
    if kwargs and not args:
        # dict(a=1, b=2, c=4)
        items = [(nodes.Const(key), value) for key, value in kwargs]
    elif len(args) == 1 and kwargs:
        # dict(some_iterable, b=2, c=4)
        elts = _get_elts(args[0], context)
        keys = [(nodes.Const(key), value) for key, value in kwargs]
        items = elts + keys
    elif len(args) == 1:
        items = _get_elts(args[0], context)
    else:
        raise UseInferenceDefault()
    value = nodes.Dict(col_offset=node.col_offset,
                       lineno=node.lineno,
                       parent=node.parent)
    value.postinit(items)
    return value
Пример #16
0
def infer_type_sub(node, context=None):
    """
    Infer a type[...] subscript

    :param node: node to infer
    :type node: astroid.nodes.node_classes.NodeNG
    :param context: inference context
    :type context: astroid.context.InferenceContext
    :return: the inferred node
    :rtype: nodes.NodeNG
    """
    node_scope, _ = node.scope().lookup("type")
    if node_scope.qname() != "builtins":
        raise UseInferenceDefault()
    class_src = """
    class type:
        def __class_getitem__(cls, key):
            return cls
     """
    node = extract_node(class_src)
    return node.infer(context=context)
Пример #17
0
def _find_func_form_arguments(node, context):
    def _extract_namedtuple_arg_or_keyword(  # pylint: disable=inconsistent-return-statements
        position, key_name=None
    ):
        if len(args) > position:
            return _infer_first(args[position], context)
        if key_name and key_name in found_keywords:
            return _infer_first(found_keywords[key_name], context)

    args = node.args
    keywords = node.keywords
    found_keywords = (
        {keyword.arg: keyword.value for keyword in keywords} if keywords else {}
    )

    name = _extract_namedtuple_arg_or_keyword(position=0, key_name="typename")
    names = _extract_namedtuple_arg_or_keyword(position=1, key_name="field_names")
    if name and names:
        return name.value, names

    raise UseInferenceDefault()
Пример #18
0
def infer_dict_fromkeys(node, context=None):
    """Infer dict.fromkeys

    :param nodes.Call node: dict.fromkeys() call to infer
    :param context.InferenceContext context: node context
    :rtype nodes.Dict:
        a Dictionary containing the values that astroid was able to infer.
        In case the inference failed for any reason, an empty dictionary
        will be inferred instead.
    """
    def _build_dict_with_elements(elements):
        new_node = nodes.Dict(col_offset=node.col_offset,
                              lineno=node.lineno,
                              parent=node.parent)
        new_node.postinit(elements)
        return new_node

    call = arguments.CallSite.from_call(node, context=context)
    if call.keyword_arguments:
        raise UseInferenceDefault(
            "TypeError: int() must take no keyword arguments")
    if len(call.positional_arguments) not in {1, 2}:
        raise UseInferenceDefault(
            "TypeError: Needs between 1 and 2 positional arguments")

    default = nodes.Const(None)
    values = call.positional_arguments[0]
    try:
        inferred_values = next(values.infer(context=context))
    except (InferenceError, StopIteration):
        return _build_dict_with_elements([])
    if inferred_values is util.Uninferable:
        return _build_dict_with_elements([])

    # Limit to a couple of potential values, as this can become pretty complicated
    accepted_iterable_elements = (nodes.Const, )
    if isinstance(inferred_values, (nodes.List, nodes.Set, nodes.Tuple)):
        elements = inferred_values.elts
        for element in elements:
            if not isinstance(element, accepted_iterable_elements):
                # Fallback to an empty dict
                return _build_dict_with_elements([])

        elements_with_value = [(element, default) for element in elements]
        return _build_dict_with_elements(elements_with_value)
    if isinstance(inferred_values, nodes.Const) and isinstance(
            inferred_values.value, (str, bytes)):
        elements = [(nodes.Const(element), default)
                    for element in inferred_values.value]
        return _build_dict_with_elements(elements)
    if isinstance(inferred_values, nodes.Dict):
        keys = inferred_values.itered()
        for key in keys:
            if not isinstance(key, accepted_iterable_elements):
                # Fallback to an empty dict
                return _build_dict_with_elements([])

        elements_with_value = [(element, default) for element in keys]
        return _build_dict_with_elements(elements_with_value)

    # Fallback to an empty dictionary
    return _build_dict_with_elements([])