Esempio n. 1
0
def infer_named_tuple(
        node: nodes.Call,
        context: InferenceContext | None = None) -> Iterator[nodes.ClassDef]:
    """Specific inference function for namedtuple Call node"""
    tuple_base_name: list[nodes.NodeNG] = [
        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])
Esempio n. 2
0
 def visit_call(self, node: nodes.Call) -> None:
     if isinstance(node.func, nodes.Name):
         name = node.func.name
         # ignore the name if it's not a builtin (i.e. not defined in the
         # locals nor globals scope)
         if not (name in node.frame(future=True) or name in node.root()):
             if name in self.linter.config.bad_functions:
                 hint = BUILTIN_HINTS.get(name)
                 args = f"{name!r}. {hint}" if hint else repr(name)
                 self.add_message("bad-builtin", node=node, args=args)
Esempio n. 3
0
    def _check_use_maxsplit_arg(self, node: nodes.Call) -> None:
        """Add message when accessing first or last elements of a str.split() or str.rsplit()."""

        # Check if call is split() or rsplit()
        if not (isinstance(node.func, nodes.Attribute)
                and node.func.attrname in {"split", "rsplit"} and isinstance(
                    utils.safe_infer(node.func), astroid.BoundMethod)):
            return

        try:
            utils.get_argument_from_call(node, 0, "sep")
        except utils.NoSuchArgumentError:
            return

        try:
            # Ignore if maxsplit arg has been set
            utils.get_argument_from_call(node, 1, "maxsplit")
            return
        except utils.NoSuchArgumentError:
            pass

        if isinstance(node.parent, nodes.Subscript):
            try:
                subscript_value = utils.get_subscript_const_value(
                    node.parent).value
            except utils.InferredTypeError:
                return

            # Check for cases where variable (Name) subscripts may be mutated within a loop
            if isinstance(node.parent.slice, nodes.Name):
                # Check if loop present within the scope of the node
                scope = node.scope()
                for loop_node in scope.nodes_of_class(
                    (nodes.For, nodes.While)):
                    if not loop_node.parent_of(node):
                        continue

                    # Check if var is mutated within loop (Assign/AugAssign)
                    for assignment_node in loop_node.nodes_of_class(
                            nodes.AugAssign):
                        if node.parent.slice.name == assignment_node.target.name:
                            return
                    for assignment_node in loop_node.nodes_of_class(
                            nodes.Assign):
                        if node.parent.slice.name in [
                                n.name for n in assignment_node.targets
                        ]:
                            return

            if subscript_value in (-1, 0):
                fn_name = node.func.attrname
                new_fn = "rsplit" if subscript_value == -1 else "split"
                new_name = (
                    node.func.as_string().rsplit(fn_name, maxsplit=1)[0] +
                    new_fn +
                    f"({node.args[0].as_string()}, maxsplit=1)[{subscript_value}]"
                )
                self.add_message("use-maxsplit-arg",
                                 node=node,
                                 args=(new_name, ))
Esempio n. 4
0
 def visit_call(self, node: nodes.Call) -> None:
     """Visit a Call node -> check if this is not a disallowed builtin
     call and check for * or ** use.
     """
     self._check_misplaced_format_function(node)
     if isinstance(node.func, nodes.Name):
         name = node.func.name
         # ignore the name if it's not a builtin (i.e. not defined in the
         # locals nor globals scope)
         if not (name in node.frame(future=True) or name in node.root()):
             if name == "exec":
                 self.add_message("exec-used", node=node)
             elif name == "reversed":
                 self._check_reversed(node)
             elif name == "eval":
                 self.add_message("eval-used", node=node)
Esempio n. 5
0
    def visit_call(self, node: nodes.Call) -> None:
        """Called when a :class:`.nodes.Call` node is visited.

        See :mod:`astroid` for the description of available nodes.
        """
        if not (isinstance(node.func, nodes.Attribute)
                and isinstance(node.func.expr, nodes.Name)
                and node.func.expr.name == self.config.store_locals_indicator
                and node.func.attrname == "create"):
            return
        in_class = node.frame()
        for param in node.args:
            in_class.locals[param.name] = node
Esempio n. 6
0
def _looks_like_pattern_or_match(node: nodes.Call) -> bool:
    """Check for re.Pattern or re.Match call in stdlib.

    Match these patterns from stdlib/re.py
    ```py
    Pattern = type(...)
    Match = type(...)
    ```
    """
    return (node.root().name == "re" and isinstance(node.func, nodes.Name)
            and node.func.name == "type"
            and isinstance(node.parent, nodes.Assign)
            and len(node.parent.targets) == 1
            and isinstance(node.parent.targets[0], nodes.AssignName)
            and node.parent.targets[0].name in ("Pattern", "Match"))
Esempio n. 7
0
 def _check_consider_iterating_dictionary(self, node: nodes.Call) -> None:
     if not isinstance(node.func, nodes.Attribute):
         return
     if node.func.attrname != "keys":
         return
     comp_ancestor = utils.get_node_first_ancestor_of_type(
         node, nodes.Compare)
     if (isinstance(
             node.parent,
         (nodes.For, nodes.Comprehension)) or comp_ancestor and any(
             op for op, comparator in comp_ancestor.ops
             if op in {"in", "not in"} and
             (comparator in node.node_ancestors() or comparator is node))):
         inferred = utils.safe_infer(node.func)
         if not isinstance(inferred, astroid.BoundMethod) or not isinstance(
                 inferred.bound, nodes.Dict):
             return
         self.add_message("consider-iterating-dictionary", node=node)