Пример #1
0
    def igetattr(self, name, context=None):
        """inferred getattr"""
        if not context:
            context = InferenceContext()
        try:
            context.lookupname = name
            # avoid recursively inferring the same attr on the same class
            if context.push(self._proxied):
                raise InferenceError(
                    message="Cannot infer the same attribute again",
                    node=self,
                    context=context,
                )

            # XXX frame should be self._proxied, or not ?
            get_attr = self.getattr(name, context, lookupclass=False)
            yield from _infer_stmts(self._wrap_attr(get_attr, context),
                                    context,
                                    frame=self)
        except AttributeInferenceError:
            try:
                # fallback to class.igetattr since it has some logic to handle
                # descriptors
                # But only if the _proxied is the Class.
                if self._proxied.__class__.__name__ != "ClassDef":
                    raise
                attrs = self._proxied.igetattr(name,
                                               context,
                                               class_context=False)
                yield from self._wrap_attr(attrs, context)
            except AttributeInferenceError as error:
                raise InferenceError(**vars(error)) from error
Пример #2
0
def infer_import_from(self, context=None, asname=True):
    """infer a ImportFrom node: return the imported module/object"""
    name = context.lookupname
    if name is None:
        raise InferenceError(node=self, context=context)
    if asname:
        try:
            name = self.real_name(name)
        except AttributeInferenceError as exc:
            # See https://github.com/PyCQA/pylint/issues/4692
            raise InferenceError(node=self, context=context) from exc
    try:
        module = self.do_import_module()
    except AstroidBuildingError as exc:
        raise InferenceError(node=self, context=context) from exc

    try:
        context = copy_context(context)
        context.lookupname = name
        stmts = module.getattr(name, ignore_locals=module is self.root())
        return bases._infer_stmts(stmts, context)
    except AttributeInferenceError as error:
        raise InferenceError(
            str(error), target=self, attribute=name, context=context
        ) from error
Пример #3
0
def infer_global(self, context=None, lookupname=None):
    if lookupname is None:
        raise InferenceError()
    try:
        return _infer_stmts(self.root().getattr(lookupname), context)
    except NotFoundError:
        raise InferenceError()
Пример #4
0
def infer_subscript(self, context=None):
    """infer simple subscription such as [1,2,3][0] or (1,2,3)[-1]"""
    value = next(self.value.infer(context))
    if value is YES:
        yield YES
        return

    index = next(self.slice.infer(context))
    if index is YES:
        yield YES
        return

    if isinstance(index, nodes.Const):
        try:
            assigned = value.getitem(index.value, context)
        except AttributeError:
            raise InferenceError()
        except (IndexError, TypeError):
            yield YES
            return

        # Prevent inferring if the infered subscript
        # is the same as the original subscripted object.
        if self is assigned:
            yield YES
            return
        for infered in assigned.infer(context):
            yield infered
    else:
        raise InferenceError()
Пример #5
0
def infer_subscript(
    self: nodes.Subscript,
    context: InferenceContext | None = None,
    **kwargs: Any
) -> Generator[InferenceResult, None, InferenceErrorInfo | None]:
    """Inference for subscripts

    We're understanding if the index is a Const
    or a slice, passing the result of inference
    to the value's `getitem` method, which should
    handle each supported index type accordingly.
    """

    found_one = False
    for value in self.value.infer(context):
        if value is util.Uninferable:
            yield util.Uninferable
            return None
        for index in self.slice.infer(context):
            if index is util.Uninferable:
                yield util.Uninferable
                return None

            # Try to deduce the index value.
            index_value = _SUBSCRIPT_SENTINEL
            if value.__class__ == bases.Instance:
                index_value = index
            elif index.__class__ == bases.Instance:
                instance_as_index = helpers.class_instance_as_index(index)
                if instance_as_index:
                    index_value = instance_as_index
            else:
                index_value = index

            if index_value is _SUBSCRIPT_SENTINEL:
                raise InferenceError(node=self, context=context)

            try:
                assigned = value.getitem(index_value, context)
            except (
                    AstroidTypeError,
                    AstroidIndexError,
                    AttributeInferenceError,
                    AttributeError,
            ) as exc:
                raise InferenceError(node=self, context=context) from exc

            # Prevent inferring if the inferred subscript
            # is the same as the original subscripted object.
            if self is assigned or assigned is util.Uninferable:
                yield util.Uninferable
                return None
            yield from assigned.infer(context)
            found_one = True

    if found_one:
        return InferenceErrorInfo(node=self, context=context)
    return None
Пример #6
0
def infer_global(self, context=None):
    if context.lookupname is None:
        raise InferenceError(node=self, context=context)
    try:
        return bases._infer_stmts(self.root().getattr(context.lookupname), context)
    except AttributeInferenceError as error:
        raise InferenceError(
            str(error), target=self, attribute=context.lookupname, context=context
        ) from error
Пример #7
0
def infer_from(self, context=None, asname=True, lookupname=None):
    """infer a From nodes: return the imported module/object"""
    if lookupname is None:
        raise InferenceError()
    if asname:
        lookupname = self.real_name(lookupname)
    module = self.do_import_module()
    try:
        return _infer_stmts(module.getattr(lookupname, ignore_locals=module is self.root()), context, lookupname=lookupname)
    except NotFoundError:
        raise InferenceError(lookupname)
Пример #8
0
def infer_global(self: nodes.Global,
                 context: InferenceContext | None = None,
                 **kwargs: Any) -> Generator[InferenceResult, None, None]:
    if context is None or context.lookupname is None:
        raise InferenceError(node=self, context=context)
    try:
        return bases._infer_stmts(self.root().getattr(context.lookupname),
                                  context)
    except AttributeInferenceError as error:
        raise InferenceError(str(error),
                             target=self,
                             attribute=context.lookupname,
                             context=context) from error
Пример #9
0
def raise_if_nothing_inferred(func, instance, args, kwargs):
    generator = func(*args, **kwargs)
    try:
        yield next(generator)
    except StopIteration as error:
        # generator is empty
        if error.args:
            # pylint: disable=not-a-mapping
            raise InferenceError(**error.args[0]) from error
        raise InferenceError(
            "StopIteration raised without any error information.") from error

    yield from generator
Пример #10
0
def infer_import(self, context=None, asname=True):
    """infer an Import node: return the imported module/object"""
    name = context.lookupname
    if name is None:
        raise InferenceError(node=self, context=context)

    try:
        if asname:
            yield self.do_import_module(self.real_name(name))
        else:
            yield self.do_import_module(name)
    except AstroidBuildingError as exc:
        raise InferenceError(node=self, context=context) from exc
Пример #11
0
def starred_assigned_stmts(self, node=None, context=None, asspath=None):
    stmt = self.statement()
    if not isinstance(stmt, (nodes.Assign, nodes.For)):
        raise InferenceError()

    if isinstance(stmt, nodes.Assign):
        value = stmt.value
        lhs = stmt.targets[0]

        if sum(1 for node in lhs.nodes_of_class(nodes.Starred)) > 1:
            # Too many starred arguments in the expression.
            raise InferenceError()

        if context is None:
            context = InferenceContext()
        try:
            rhs = next(value.infer(context))
        except InferenceError:
            yield YES
            return
        if rhs is YES or not hasattr(rhs, 'elts'):
            # Not interested in inferred values without elts.
            yield YES
            return

        elts = collections.deque(rhs.elts[:])
        if len(lhs.elts) > len(rhs.elts):
            # a, *b, c = (1, 2)
            raise InferenceError()

        # Unpack iteratively the values from the rhs of the assignment,
        # until the find the starred node. What will remain will
        # be the list of values which the Starred node will represent
        # This is done in two steps, from left to right to remove
        # anything before the starred node and from right to left
        # to remvoe anything after the starred node.

        for index, node in enumerate(lhs.elts):
            if not isinstance(node, nodes.Starred):
                elts.popleft()
                continue
            lhs_elts = collections.deque(reversed(lhs.elts[index:]))
            for node in lhs_elts:
                if not isinstance(node, nodes.Starred):
                    elts.pop()
                    continue
                # We're done
                for elt in elts:
                    yield elt
                break
Пример #12
0
def infer_from(self, context=None, asname=True):
    """infer a From nodes: return the imported module/object"""
    name = context.lookupname
    if name is None:
        raise InferenceError()
    if asname:
        name = self.real_name(name)
    module = self.do_import_module(self.modname)
    try:
        context = copy_context(context)
        context.lookupname = name
        return _infer_stmts(
            module.getattr(name, ignore_locals=module is self.root()), context)
    except NotFoundError:
        raise InferenceError(name)
Пример #13
0
 def infer_call_result(self, caller=None, context=None):
     nonlocal func_setter
     if caller and len(caller.args) != 2:
         raise InferenceError(
             "fset() needs two arguments", target=self, context=context
         )
     yield from func_setter.infer_call_result(caller=caller, context=context)
Пример #14
0
def infer_arguments(self: nodes.Arguments,
                    context: InferenceContext | None = None,
                    **kwargs: Any) -> Generator[InferenceResult, None, None]:
    if context is None or context.lookupname is None:
        raise InferenceError(node=self, context=context)
    return protocols._arguments_infer_argname(self, context.lookupname,
                                              context)
Пример #15
0
def infer_typing_namedtuple_class(class_node, context=None):
    """Infer a subclass of typing.NamedTuple"""
    # Check if it has the corresponding bases
    annassigns_fields = [
        annassign.target.name
        for annassign in class_node.body
        if isinstance(annassign, nodes.AnnAssign)
    ]
    code = dedent(
        """
    from collections import namedtuple
    namedtuple({typename!r}, {fields!r})
    """
    ).format(typename=class_node.name, fields=",".join(annassigns_fields))
    node = extract_node(code)
    try:
        generated_class_node = next(infer_named_tuple(node, context))
    except StopIteration as e:
        raise InferenceError(node=node, context=context) from e
    for method in class_node.mymethods():
        generated_class_node.locals[method.name] = [method]

    for body_node in class_node.body:
        if isinstance(body_node, nodes.Assign):
            for target in body_node.targets:
                attr = target.name
                generated_class_node.locals[attr] = class_node.locals[attr]
        elif isinstance(body_node, nodes.ClassDef):
            generated_class_node.locals[body_node.name] = [body_node]

    return iter((generated_class_node,))
Пример #16
0
def _infer_stmts(stmts, context, frame=None, lookupname=None):
    """return an iterator on statements inferred by each statement in <stmts>
    """
    stmt = None
    infered = False
    if context is None:
        context = InferenceContext()
    for stmt in stmts:
        if stmt is YES:
            yield stmt
            infered = True
            continue

        kw = {}
        infered_name = stmt._infer_name(frame, lookupname)
        if infered_name is not None:
            # only returns not None if .infer() accepts a lookupname kwarg
            kw['lookupname'] = infered_name

        try:
            for infered in stmt.infer(context, **kw):
                yield infered
                infered = True
        except UnresolvableName:
            continue
        except InferenceError:
            yield YES
            infered = True
    if not infered:
        raise InferenceError(str(stmt))
Пример #17
0
 def wrapper(*args, **kwargs):
     infered = False
     for node in func(*args, **kwargs):
         infered = True
         yield node
     if not infered:
         raise InferenceError()
Пример #18
0
def _infer_stmts(stmts, context, frame=None):
    """Return an iterator on statements inferred by each statement in *stmts*."""
    inferred = False
    if context is not None:
        name = context.lookupname
        context = context.clone()
    else:
        name = None
        context = InferenceContext()

    for stmt in stmts:
        if stmt is Uninferable:
            yield stmt
            inferred = True
            continue
        context.lookupname = stmt._infer_name(frame, name)
        try:
            for inf in stmt.infer(context=context):
                yield inf
                inferred = True
        except NameInferenceError:
            continue
        except InferenceError:
            yield Uninferable
            inferred = True
    if not inferred:
        raise InferenceError(
            "Inference failed for all members of {stmts!r}.",
            stmts=stmts,
            frame=frame,
            context=context,
        )
Пример #19
0
 def igetattr(self, name, context=None):
     """inferred getattr, need special treatment in class to handle
     descriptors
     """
     # set lookup name since this is necessary to infer on import nodes for
     # instance
     context = copy_context(context)
     context.lookupname = name
     try:
         for infered in _infer_stmts(self.getattr(name, context),
                                     context,
                                     frame=self):
             # yield YES object instead of descriptors when necessary
             if not isinstance(infered, Const) and isinstance(
                     infered, Instance):
                 try:
                     infered._proxied.getattr('__get__', context)
                 except NotFoundError:
                     yield infered
                 else:
                     yield YES
             else:
                 yield function_to_method(infered, self)
     except NotFoundError:
         if not name.startswith('__') and self.has_dynamic_getattr(context):
             # class handle some dynamic attributes, return a YES object
             yield YES
         else:
             raise InferenceError(name)
Пример #20
0
def _infer_stmts(stmts, context, frame=None):
    """return an iterator on statements inferred by each statement in <stmts>
    """
    stmt = None
    infered = False
    if context is not None:
        name = context.lookupname
        context = context.clone()
    else:
        name = None
        context = InferenceContext()
    for stmt in stmts:
        if stmt is YES:
            yield stmt
            infered = True
            continue
        context.lookupname = stmt._infer_name(frame, name)
        try:
            for infered in stmt.infer(context):
                yield infered
                infered = True
        except UnresolvableName:
            continue
        except InferenceError:
            yield YES
            infered = True
    if not infered:
        raise InferenceError(str(stmt))
Пример #21
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])
Пример #22
0
def infer_import(self, context=None, asname=True, lookupname=None):
    """infer an Import node: return the imported module/object"""
    if lookupname is None:
        raise InferenceError()
    if asname:
        yield self.do_import_module(self.real_name(lookupname))
    else:
        yield self.do_import_module(lookupname)
Пример #23
0
def _infer_context_manager(self, mgr, context):
    try:
        inferred = next(mgr.infer(context=context))
    except StopIteration as e:
        raise InferenceError(node=mgr) from e
    if isinstance(inferred, bases.Generator):
        # Check if it is decorated with contextlib.contextmanager.
        func = inferred.parent
        if not func.decorators:
            raise InferenceError(
                "No decorators found on inferred generator %s", node=func)

        for decorator_node in func.decorators.nodes:
            decorator = next(decorator_node.infer(context=context), None)
            if isinstance(decorator, nodes.FunctionDef):
                if decorator.qname() == _CONTEXTLIB_MGR:
                    break
        else:
            # It doesn't interest us.
            raise InferenceError(node=func)
        try:
            yield next(inferred.infer_yield_types())
        except StopIteration as e:
            raise InferenceError(node=func) from e

    elif isinstance(inferred, bases.Instance):
        try:
            enter = next(inferred.igetattr("__enter__", context=context))
        except (InferenceError, AttributeInferenceError, StopIteration) as exc:
            raise InferenceError(node=inferred) from exc
        if not isinstance(enter, bases.BoundMethod):
            raise InferenceError(node=enter)
        yield from enter.infer_call_result(self, context)
    else:
        raise InferenceError(node=mgr)
Пример #24
0
            def infer_call_result(self, caller, context=None):
                if len(caller.args) > 2 or len(caller.args) < 1:
                    raise InferenceError(
                        "Invalid arguments for descriptor binding",
                        target=self,
                        context=context,
                    )

                context = copy_context(context)
                try:
                    cls = next(caller.args[0].infer(context=context))
                except StopIteration as e:
                    raise InferenceError(context=context, node=caller.args[0]) from e

                if cls is astroid.Uninferable:
                    raise InferenceError(
                        "Invalid class inferred", target=self, context=context
                    )

                # For some reason func is a Node that the below
                # code is not expecting
                if isinstance(func, bases.BoundMethod):
                    yield func
                    return

                # Rebuild the original value, but with the parent set as the
                # class where it will be bound.
                new_func = func.__class__(
                    name=func.name,
                    lineno=func.lineno,
                    col_offset=func.col_offset,
                    parent=func.parent,
                )
                # pylint: disable=no-member
                new_func.postinit(
                    func.args,
                    func.body,
                    func.decorators,
                    func.returns,
                    doc_node=func.doc_node,
                )

                # Build a proper bound method that points to our newly built function.
                proxy = bases.UnboundMethod(new_func)
                yield bases.BoundMethod(proxy=proxy, bound=cls)
Пример #25
0
            def infer_call_result(self, caller=None, context=None):
                nonlocal func
                if caller and len(caller.args) != 1:
                    raise InferenceError("fget() needs a single argument",
                                         target=self,
                                         context=context)

                yield from func.function.infer_call_result(caller=caller,
                                                           context=context)
Пример #26
0
 def infer_call_result(self, caller, context=None):
     """infer what a class instance is returning when called"""
     infered = False
     for node in self._proxied.igetattr('__call__', context):
         for res in node.infer_call_result(caller, context):
             infered = True
             yield res
     if not infered:
         raise InferenceError()
Пример #27
0
 def _infer(
     self,
     context: InferenceContext | None = None,
     **kwargs: Any
 ) -> Generator[InferenceResult, None, InferenceErrorInfo | None]:
     """we don't know how to resolve a statement by default"""
     # this method is overridden by most concrete classes
     raise InferenceError("No inference function for {node!r}.",
                          node=self,
                          context=context)
Пример #28
0
def infer_import(
    self: nodes.Import,
    context: InferenceContext | None = None,
    asname: bool = True,
    **kwargs: Any,
) -> Generator[nodes.Module, None, None]:
    """infer an Import node: return the imported module/object"""
    context = context or InferenceContext()
    name = context.lookupname
    if name is None:
        raise InferenceError(node=self, context=context)

    try:
        if asname:
            yield self.do_import_module(self.real_name(name))
        else:
            yield self.do_import_module(name)
    except AstroidBuildingError as exc:
        raise InferenceError(node=self, context=context) from exc
Пример #29
0
def _infer_map(node, context):
    """Infer all values based on Dict.items"""
    values = {}
    for name, value in node.items:
        if isinstance(name, nodes.DictUnpack):
            double_starred = helpers.safe_infer(value, context)
            if not double_starred:
                raise InferenceError
            if not isinstance(double_starred, nodes.Dict):
                raise InferenceError(node=node, context=context)
            unpack_items = _infer_map(double_starred, context)
            values = _update_with_replacement(values, unpack_items)
        else:
            key = helpers.safe_infer(name, context=context)
            value = helpers.safe_infer(value, context=context)
            if any(not elem for elem in (key, value)):
                raise InferenceError(node=node, context=context)
            values = _update_with_replacement(values, {key: value})
    return values
Пример #30
0
 def igetattr(self, name, context=None):
     """inferred getattr"""
     # set lookup name since this is necessary to infer on import nodes for
     # instance
     if not context:
         context = InferenceContext()
     try:
         return _infer_stmts(self.getattr(name, context), context, frame=self, lookupname=name)
     except NotFoundError:
         raise InferenceError(name)