def _supports_protocol( value: astroid.node_classes.NodeNG, protocol_callback: astroid.FunctionDef ) -> bool: if isinstance(value, astroid.ClassDef): if not has_known_bases(value): return True # classobj can only be iterable if it has an iterable metaclass meta = value.metaclass() if meta is not None: if protocol_callback(meta): return True if isinstance(value, astroid.BaseInstance): if not has_known_bases(value): return True if value.has_dynamic_getattr(): return True if protocol_callback(value): return True # TODO: this is not needed in astroid 2.0, where we can # check the type using a virtual base class instead. if ( isinstance(value, _bases.Proxy) and isinstance(value._proxied, astroid.BaseInstance) and has_known_bases(value._proxied) ): value = value._proxied return protocol_callback(value) return False
def inherit_from_std_ex(node: astroid.node_classes.NodeNG) -> bool: """ Return true if the given class node is subclass of exceptions.Exception. """ if node.name in ('Exception', 'BaseException') \ and node.root().name == EXCEPTIONS_MODULE: return True if not hasattr(node, 'ancestors'): return False return any(inherit_from_std_ex(parent) for parent in node.ancestors(recurs=True))
def overrides_a_method(class_node: astroid.node_classes.NodeNG, name: str) -> bool: """return True if <name> is a method overridden from an ancestor""" for ancestor in class_node.ancestors(): if name in ancestor and isinstance(ancestor[name], astroid.FunctionDef): return True return False
def is_super(node: astroid.node_classes.NodeNG) -> bool: """return True if the node is referencing the "super" builtin function """ if getattr(node, 'name', None) == 'super' and \ node.root().name == BUILTINS_NAME: return True return False
def unimplemented_abstract_methods( node: astroid.node_classes.NodeNG, is_abstract_cb: astroid.FunctionDef = None ) -> Dict[str, astroid.node_classes.NodeNG]: """ Get the unimplemented abstract methods for the given *node*. A method can be considered abstract if the callback *is_abstract_cb* returns a ``True`` value. The check defaults to verifying that a method is decorated with abstract methods. The function will work only for new-style classes. For old-style classes, it will simply return an empty dictionary. For the rest of them, it will return a dictionary of abstract method names and their inferred objects. """ if is_abstract_cb is None: is_abstract_cb = partial(decorated_with, qnames=ABC_METHODS) visited = {} # type: Dict[str, astroid.node_classes.NodeNG] try: mro = reversed(node.mro()) except NotImplementedError: # Old style class, it will not have a mro. return {} except astroid.ResolveError: # Probably inconsistent hierarchy, don'try # to figure this out here. return {} for ancestor in mro: for obj in ancestor.values(): infered = obj if isinstance(obj, astroid.AssignName): infered = safe_infer(obj) if not infered: # Might be an abstract function, # but since we don't have enough information # in order to take this decision, we're taking # the *safe* decision instead. if obj.name in visited: del visited[obj.name] continue if not isinstance(infered, astroid.FunctionDef): if obj.name in visited: del visited[obj.name] if isinstance(infered, astroid.FunctionDef): # It's critical to use the original name, # since after inferring, an object can be something # else than expected, as in the case of the # following assignment. # # class A: # def keys(self): pass # __iter__ = keys abstract = is_abstract_cb(infered) if abstract: visited[obj.name] = infered elif not abstract and obj.name in visited: del visited[obj.name] return visited
def is_postponed_evaluation_enabled(node: astroid.node_classes.NodeNG) -> bool: """Check if the postponed evaluation of annotations is enabled""" name = "annotations" module = node.root() stmt = module.locals.get(name) return ( stmt and isinstance(stmt[0], astroid.ImportFrom) and stmt[0].modname == "__future__" )
def _supports_protocol_method(value: astroid.node_classes.NodeNG, attr: str) -> bool: try: attributes = value.getattr(attr) except astroid.NotFoundError: return False first = attributes[0] if isinstance(first, astroid.AssignName): if isinstance(first.parent.value, astroid.Const): return False return True
def is_default_argument(node: astroid.node_classes.NodeNG) -> bool: """return true if the given Name node is used in function or lambda default argument's value """ parent = node.scope() if isinstance(parent, (astroid.FunctionDef, astroid.Lambda)): for default_node in parent.args.defaults: for default_name_node in default_node.nodes_of_class(astroid.Name): if default_name_node is node: return True return False
def node_frame_class(node: astroid.node_classes.NodeNG) -> Optional[astroid.node_classes.NodeNG]: """return klass node for a method node (or a staticmethod or a classmethod), return null otherwise """ klass = node.frame() while klass is not None and not isinstance(klass, astroid.ClassDef): if klass.parent is None: klass = None else: klass = klass.parent.frame() return klass
def is_defined_in_scope( var_node: astroid.node_classes.NodeNG, varname: str, scope: astroid.node_classes.NodeNG, ) -> bool: if isinstance(scope, astroid.If): for node in scope.body: if ( isinstance(node, astroid.Assign) and any( isinstance(target, astroid.AssignName) and target.name == varname for target in node.targets ) ) or (isinstance(node, astroid.Nonlocal) and varname in node.names): return True elif isinstance(scope, (COMP_NODE_TYPES, astroid.For)): for ass_node in scope.nodes_of_class(astroid.AssignName): if ass_node.name == varname: return True elif isinstance(scope, astroid.With): for expr, ids in scope.items: if expr.parent_of(var_node): break if ids and isinstance(ids, astroid.AssignName) and ids.name == varname: return True elif isinstance(scope, (astroid.Lambda, astroid.FunctionDef)): if scope.args.is_argument(varname): # If the name is found inside a default value # of a function, then let the search continue # in the parent's tree. if scope.args.parent_of(var_node): try: scope.args.default_value(varname) scope = scope.parent is_defined_in_scope(var_node, varname, scope) except astroid.NoDefault: pass return True if getattr(scope, "name", None) == varname: return True elif isinstance(scope, astroid.ExceptHandler): if isinstance(scope.name, astroid.AssignName): ass_node = scope.name if ass_node.name == varname: return True return False
def node_type(node: astroid.node_classes.NodeNG) -> Optional[type]: """Return the inferred type for `node` If there is more than one possible type, or if inferred type is Uninferable or None, return None """ # check there is only one possible type for the assign node. Else we # don't handle it for now types = set() try: for var_type in node.infer(): if var_type == astroid.Uninferable or is_none(var_type): continue types.add(var_type) if len(types) > 1: return None except astroid.InferenceError: return None return types.pop() if types else None
def safe_infer(node: astroid.node_classes.NodeNG, context=None) -> Optional[astroid.node_classes.NodeNG]: """Return the inferred value for the given node. Return None if inference failed or if there is some ambiguity (more than one node has been inferred). """ try: inferit = node.infer(context=context) value = next(inferit) except astroid.InferenceError: return None try: next(inferit) return None # None if there is ambiguity on the inferred node except astroid.InferenceError: return None # there is some kind of ambiguity except StopIteration: return value
def clobber_in_except(node: astroid.node_classes.NodeNG) -> Tuple[bool, Tuple[str, str]]: """Checks if an assignment node in an except handler clobbers an existing variable. Returns (True, args for W0623) if assignment clobbers an existing variable, (False, None) otherwise. """ if isinstance(node, astroid.AssignAttr): return True, (node.attrname, 'object %r' % (node.expr.as_string(),)) if isinstance(node, astroid.AssignName): name = node.name if is_builtin(name): return (True, (name, 'builtins')) stmts = node.lookup(name)[1] if (stmts and not isinstance(stmts[0].assign_type(), (astroid.Assign, astroid.AugAssign, astroid.ExceptHandler))): return True, (name, 'outer scope (line %s)' % stmts[0].fromlineno) return False, None
def clobber_in_except( node: astroid.node_classes.NodeNG, ) -> Tuple[bool, Optional[Tuple[str, str]]]: """Checks if an assignment node in an except handler clobbers an existing variable. Returns (True, args for W0623) if assignment clobbers an existing variable, (False, None) otherwise. """ if isinstance(node, astroid.AssignAttr): return True, (node.attrname, "object %r" % (node.expr.as_string(),)) if isinstance(node, astroid.AssignName): name = node.name if is_builtin(name): return True, (name, "builtins") stmts = node.lookup(name)[1] if stmts and not isinstance( stmts[0].assign_type(), (astroid.Assign, astroid.AugAssign, astroid.ExceptHandler), ): return True, (name, "outer scope (line %s)" % stmts[0].fromlineno) return False, None
def node_frame_class(node: astroid.node_classes.NodeNG) -> Optional[astroid.ClassDef]: """Return the class that is wrapping the given node The function returns a class for a method node (or a staticmethod or a classmethod), otherwise it returns `None`. """ klass = node.frame() nodes_to_check = ( astroid.node_classes.NodeNG, astroid.UnboundMethod, astroid.BaseInstance, ) while ( klass and isinstance(klass, nodes_to_check) and not isinstance(klass, astroid.ClassDef) ): if klass.parent is None: klass = None else: klass = klass.parent.frame() return klass
def is_defined_before(var_node: astroid.node_classes.NodeNG) -> bool: """return True if the variable node is defined by a parent node (list, set, dict, or generator comprehension, lambda) or in a previous sibling node on the same line (statement_defining ; statement_using) """ varname = var_node.name _node = var_node.parent while _node: if is_defined_in_scope(var_node, varname, _node): return True _node = _node.parent # possibly multiple statements on the same line using semi colon separator stmt = var_node.statement() _node = stmt.previous_sibling() lineno = stmt.fromlineno while _node and _node.fromlineno == lineno: for assign_node in _node.nodes_of_class(astroid.AssignName): if assign_node.name == varname: return True for imp_node in _node.nodes_of_class((astroid.ImportFrom, astroid.Import)): if varname in [name[1] or name[0] for name in imp_node.names]: return True _node = _node.previous_sibling() return False
def is_error(node: astroid.node_classes.NodeNG) -> bool: """return true if the function does nothing but raising an exception""" for child_node in node.get_children(): if isinstance(child_node, astroid.Raise): return True return False
def visit_generic(self, node: astroid.node_classes.NodeNG) -> None: """Propagate the visit to the children.""" for child in node.get_children(): self.visit(child)
def is_postponed_evaluation_enabled(node: astroid.node_classes.NodeNG) -> bool: """Check if the postponed evaluation of annotations is enabled""" module = node.root() return "annotations" in module.future_imports
def is_super(node: astroid.node_classes.NodeNG) -> bool: """return True if the node is referencing the "super" builtin function""" if getattr(node, "name", None) == "super" and node.root().name == BUILTINS_NAME: return True return False
def is_builtin_object(node: astroid.node_classes.NodeNG) -> bool: """Returns True if the given node is an object from the __builtin__ module.""" return node and node.root().name == BUILTINS_NAME
def is_postponed_evaluation_enabled(node: astroid.node_classes.NodeNG) -> bool: """Check if the postponed evaluation of annotations is enabled""" name = 'annotations' module = node.root() stmt = module.locals.get(name) return stmt and isinstance(stmt[0], astroid.ImportFrom) and stmt[0].modname == '__future__'