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])
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)
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"))
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)