def visit_functiondef(self, func: nodes.FunctionDef) -> None: self._current_block.add_statement(func) previous_cfg = self._current_cfg previous_block = self._current_block self.cfgs[func] = ControlFlowGraph() self._current_cfg = self.cfgs[func] self._control_boundaries.append((func, { nodes.Return.__name__: self._current_cfg.end })) self._current_cfg.start.add_statement(func.args) func.cfg_block = self._current_cfg.start self._current_block = self._current_cfg.create_block( self._current_cfg.start) for child in func.body: child.accept(self) self._control_boundaries.pop() self._current_cfg.link_or_merge(self._current_block, self._current_cfg.end) self._current_cfg.update_block_reachability() self._current_block = previous_block self._current_cfg = previous_cfg
def _determine_function_name_type(node: nodes.FunctionDef, config: argparse.Namespace) -> str: """Determine the name type whose regex the function's name should match. :param node: A function node. :param config: Configuration from which to pull additional property classes. :returns: One of ('function', 'method', 'attr') """ property_classes, property_names = _get_properties(config) if not node.is_method(): return "function" if is_property_setter(node) or is_property_deleter(node): # If the function is decorated using the prop_method.{setter,getter} # form, treat it like an attribute as well. return "attr" decorators = node.decorators.nodes if node.decorators else [] for decorator in decorators: # If the function is a property (decorated with @property # or @abc.abstractproperty), the name type is 'attr'. if isinstance( decorator, nodes.Name) or (isinstance(decorator, nodes.Attribute) and decorator.attrname in property_names): inferred = utils.safe_infer(decorator) if (inferred and hasattr(inferred, "qname") and inferred.qname() in property_classes): return "attr" return "method"
def visit_functiondef(self, node: nodes.FunctionDef) -> None: """Check function name, docstring, arguments, redefinition, variable names, max locals. """ if node.is_method(): self.linter.stats.node_count["method"] += 1 else: self.linter.stats.node_count["function"] += 1 self._check_dangerous_default(node)
def _check_nonlocal_and_global(self, node: nodes.FunctionDef) -> None: """Check that a name is both nonlocal and global.""" def same_scope(current: nodes.Global | nodes.Nonlocal) -> bool: return current.scope() is node from_iter = itertools.chain.from_iterable nonlocals = set( from_iter(child.names for child in node.nodes_of_class(nodes.Nonlocal) if same_scope(child))) if not nonlocals: return global_vars = set( from_iter(child.names for child in node.nodes_of_class(nodes.Global) if same_scope(child))) for name in nonlocals.intersection(global_vars): self.add_message("nonlocal-and-global", args=(name, ), node=node)
def visit_functiondef(self, node: nodes.FunctionDef) -> None: if not node.is_method(): return inferred = _safe_infer_call_result(node, node) # Only want to check types that we are able to infer if (inferred and node.name in self._protocol_map and not is_function_body_ellipsis(node)): self._protocol_map[node.name](node, inferred) if node.name in PYMETHODS: self._check_unexpected_method_signature(node)
def infer_typedDict( # pylint: disable=invalid-name node: nodes.FunctionDef, ctx: context.InferenceContext = None ) -> None: """Replace TypedDict FunctionDef with ClassDef.""" class_def = nodes.ClassDef( name="TypedDict", doc=node.doc, lineno=node.lineno, col_offset=node.col_offset, parent=node.parent, ) class_def.postinit(bases=[], body=[], decorators=None) node.root().locals["TypedDict"] = [class_def]
def _check_first_arg_for_type(self, node: nodes.FunctionDef) -> None: """Check the name of first argument.""" # pylint: disable=duplicate-code if node.args.posonlyargs: first_arg = node.args.posonlyargs[0].name elif node.args.args: first_arg = node.argnames()[0] else: first_arg = None self._first_attrs.append(first_arg) # static method if node.type == "staticmethod": self._first_attrs[-1] = None
def _looks_like_signal(node: nodes.FunctionDef, signal_name: str = "pyqtSignal") -> bool: """Detect a Signal node.""" klasses = node.instance_attrs.get("__class__", []) # On PySide2 or PySide6 (since Qt 5.15.2) the Signal class changed locations if node.qname().partition(".")[0] in {"PySide2", "PySide6"}: return any(cls.qname() == "Signal" for cls in klasses) # pragma: no cover if klasses: try: return klasses[0].name == signal_name except AttributeError: # pragma: no cover # return False if the cls does not have a name attribute pass return False
def _add_raise_message(self, missing_excs: set[str], node: nodes.FunctionDef) -> None: """Adds a message on :param:`node` for the missing exception type. :param missing_excs: A list of missing exception types. :param node: The node show the message on. """ if node.is_abstract(): try: missing_excs.remove("NotImplementedError") except KeyError: pass if not missing_excs: return self.add_message("missing-raises-doc", args=(", ".join(sorted(missing_excs)), ), node=node)
def visit_functiondef(self, node: nodes.FunctionDef) -> None: """Called when a FunctionDef node is visited.""" if not node.is_method() or node.name != "__init__": return # Check that all arguments are annotated. # The first argument is "self". args = node.args annotations = (args.posonlyargs_annotations + args.annotations + args.kwonlyargs_annotations)[1:] if args.vararg is not None: annotations.append(args.varargannotation) if args.kwarg is not None: annotations.append(args.kwargannotation) if not annotations or None in annotations: return # Check that return type is specified and it is "None". if not isinstance(node.returns, nodes.Const) or node.returns.value is not None: self.add_message("hass-constructor-return", node=node)
def visit_functiondef(self, node: nodes.FunctionDef) -> None: # Do not emit any warnings if the method is just an implementation # of a base class method. confidence = interfaces.HIGH if node.is_method(): if utils.overrides_a_method(node.parent.frame(future=True), node.name): return confidence = (interfaces.INFERENCE if utils.has_known_bases( node.parent.frame( future=True)) else interfaces.INFERENCE_FAILURE) self._check_name( _determine_function_name_type(node, config=self.linter.config), node.name, node, confidence, ) # Check argument names args = node.args.args if args is not None: self._recursive_check_names(args)
def visit_functiondef(self, node: nodes.FunctionDef) -> None: """check use of super""" # ignore actual functions or method within a new style class if not node.is_method(): return klass = node.parent.frame() for stmt in node.nodes_of_class(nodes.Call): if node_frame_class(stmt) != node_frame_class(node): # Don't look down in other scopes. continue expr = stmt.func if not isinstance(expr, nodes.Attribute): continue call = expr.expr # skip the test if using super if not (isinstance(call, nodes.Call) and isinstance( call.func, nodes.Name) and call.func.name == "super"): continue # super should not be used on an old style class if klass.newstyle or not has_known_bases(klass): # super first arg should not be the class if not call.args: continue # calling super(type(self), self) can lead to recursion loop # in derived classes arg0 = call.args[0] if (isinstance(arg0, nodes.Call) and isinstance(arg0.func, nodes.Name) and arg0.func.name == "type"): self.add_message("bad-super-call", node=call, args=("type", )) continue # calling super(self.__class__, self) can lead to recursion loop # in derived classes if (len(call.args) >= 2 and isinstance(call.args[1], nodes.Name) and call.args[1].name == "self" and isinstance(arg0, nodes.Attribute) and arg0.attrname == "__class__"): self.add_message("bad-super-call", node=call, args=("self.__class__", )) continue try: supcls = call.args and next(call.args[0].infer(), None) except astroid.InferenceError: continue if klass is not supcls: name = None # if supcls is not Uninferable, then supcls was inferred # and use its name. Otherwise, try to look # for call.args[0].name if supcls: name = supcls.name elif call.args and hasattr(call.args[0], "name"): name = call.args[0].name if name: self.add_message("bad-super-call", node=call, args=(name, ))
def visit_functiondef(self, node: nodes.FunctionDef) -> None: ftype = "method" if node.is_method() else "function" self._check_docstring(ftype, node)
def visit_functiondef(self, node: nodes.FunctionDef) -> None: if not node.is_method(): return self._meth_could_be_func = True self._check_first_arg_for_type(node)
def _has_bare_super_call(fundef_node: nodes.FunctionDef) -> bool: for call in fundef_node.nodes_of_class(nodes.Call): func = call.func if isinstance(func, nodes.Name) and func.name == "super" and not call.args: return True return False
def visit_functiondef(self, node: nodes.FunctionDef) -> None: """Called when a FunctionDef node is visited.""" for match in self._function_matchers: if node.name != match.function_name or node.is_method(): continue self._check_function(node, match)