def visit_return(self,node): if not isinstance(node.parent,astroid.FunctionDef) or node.parent.name!="get_rule": return if not node.is_tuple_return(): return name = node.value.getitem(astroid.Const(0)).as_string() if name not in self.cl: return details = node.value.getitem(astroid.Const(1)) if not isinstance(details,astroid.Call): return try : ccrtype = next(x.value for x in details.keywords if x.arg == "ccrtype") if self.cl[name] == ["MappingRule"]: self.add_message("mapping-rule-is-not-ccr",node=node) try : problematic_name = next(x for x in details.keywords if x.arg =="name") self.add_message("ccr-rule-details-have-no-name",node=problematic_name) except StopIteration: pass if ccrtype.as_string()=="CCRType.GLOBAL": if any(x for x in details.keywords if x.arg in ["executable","title","handle","function_context"]): self.add_message("global-no-context",node=node) if "BaseSelfModifyingRule" in self.cl and ccrtype.as_string()!="CCRType.SELFMOD": self.add_message("incorrect-ccrtype-selfmod",node=ccrtype) except StopIteration: pass
def test_inference_invalid_slice(node): sub_node = astroid.Subscript() slice = astroid.Slice() slice.postinit(astroid.Const(0), astroid.Const('a')) sub_node.postinit(node, slice) module, _ = cs._parse_text(sub_node) for subscript_node in module.nodes_of_class(astroid.Subscript): assert isinstance(subscript_node.inf_type, TypeFail)
def test_annotation_positional_only(self): ast_node = builder.extract_node(""" def test(a: 1, b: 2, /, c: 3): pass test.__annotations__ #@ """) annotations = next(ast_node.infer()) self.assertIsInstance(annotations, astroid.Dict) self.assertIsInstance(annotations.getitem(astroid.Const("a")), astroid.Const) self.assertEqual(annotations.getitem(astroid.Const("a")).value, 1) self.assertEqual(annotations.getitem(astroid.Const("b")).value, 2) self.assertEqual(annotations.getitem(astroid.Const("c")).value, 3)
def var_annotations_filter(node: nc.NodeNG) -> nc.NodeNG: """Filter annotated function variable assigns. This accounts for deferred evaluation. """ if using_future_annotations(node): # Future behavior: # Annotations are never evaluated. willeval = False else: # Legacy behavior: # Annotated assigns under functions are not evaluated, # but class or module vars are. fnode = node willeval = True while fnode is not None: if isinstance(fnode, (astroid.FunctionDef, astroid.AsyncFunctionDef)): willeval = False break if isinstance(fnode, astroid.ClassDef): willeval = True break fnode = fnode.parent # If this annotation won't be eval'ed, replace it with a dummy string. if not willeval: dummyval = astroid.Const(parent=node, value='dummyval') node.annotation = dummyval return node
def test_all_elements_without_parent(self): node = astroid.extract_node("__all__ = []") node.value.elts.append(astroid.Const("test")) root = node.root() with self.assertNoMessages(): self.checker.visit_module(root) self.checker.leave_module(root)
def test_instance_special_model(self): ast_nodes = builder.extract_node( """ class A: "test" def __init__(self): self.a = 42 a = A() a.__class__ #@ a.__module__ #@ a.__doc__ #@ a.__dict__ #@ """, module_name="fake_module", ) cls = next(ast_nodes[0].infer()) self.assertIsInstance(cls, astroid.ClassDef) self.assertEqual(cls.name, "A") module = next(ast_nodes[1].infer()) self.assertIsInstance(module, astroid.Const) self.assertEqual(module.value, "fake_module") doc = next(ast_nodes[2].infer()) self.assertIsInstance(doc, astroid.Const) self.assertEqual(doc.value, "test") dunder_dict = next(ast_nodes[3].infer()) self.assertIsInstance(dunder_dict, astroid.Dict) attr = next(dunder_dict.getitem(astroid.Const("a")).infer()) self.assertIsInstance(attr, astroid.Const) self.assertEqual(attr.value, 42)
def test_instance_special_model(self): ast_nodes = builder.extract_node(''' class A: "test" def __init__(self): self.a = 42 a = A() a.__class__ #@ a.__module__ #@ a.__doc__ #@ a.__dict__ #@ ''', module_name='collections') cls = next(ast_nodes[0].infer()) self.assertIsInstance(cls, astroid.ClassDef) self.assertEqual(cls.name, 'A') module = next(ast_nodes[1].infer()) self.assertIsInstance(module, astroid.Const) self.assertEqual(module.value, 'collections') doc = next(ast_nodes[2].infer()) self.assertIsInstance(doc, astroid.Const) self.assertEqual(doc.value, 'test') dunder_dict = next(ast_nodes[3].infer()) self.assertIsInstance(dunder_dict, astroid.Dict) attr = next(dunder_dict.getitem(astroid.Const('a')).infer()) self.assertIsInstance(attr, astroid.Const) self.assertEqual(attr.value, 42)
def test_subscript_load_ctx(node): """Test visitor of Subscript node when loaded in an (if) expression.""" load_node = astroid.If() load_node.postinit(astroid.Const(True), [node]) module, _ = cs._parse_text(load_node) for subscript_node in module.nodes_of_class(astroid.Subscript): list_node = subscript_node.value assert subscript_node.inf_type.getValue() == List[list_node.elts[0].inf_type.getValue()]
def visit_binop(self, node): if node.op != '%': return if isinstance(node.left, astroid.CallFunc) and getattr( node.left.func, "name", "") in translationMethods: for formatstr in _get_message_strings(node.left): # Create a copy of the node with just the message string as the format copynode = copy(node) copynode.left = astroid.Const(formatstr) StringFormatChecker.visit_binop(self, copynode)
def visit_callfunc(self, node): if len(node.args) >= 1 and isinstance(node.args[0], astroid.CallFunc) and \ getattr(node.args[0].func, "name", "") in translationMethods: for formatstr in _get_message_strings(node.args[0]): # Both the node and the args need to be copied so we don't replace args # on the original node. copynode = copy(node) copyargs = copy(node.args) copyargs[0] = astroid.Const(formatstr) copynode.args = copyargs LoggingChecker.visit_callfunc(self, copynode)
def create_format_spec_node(node: ast.Call, value: ast.Name, format_spec: str) -> ast.FormattedValue: formatted_value_node = ast.FormattedValue(lineno=node.lineno, col_offset=node.col_offset, parent=node.parent) specifications: Optional[ast.JoinedStr] if format_spec: specifications = ast.JoinedStr(lineno=node.lineno, col_offset=node.col_offset, parent=node.parent,) specifications.postinit(values=[ast.Const(format_spec.replace(":", ""))]) else: specifications = None formatted_value_node.postinit(value=ast.Name(value.name), format_spec=specifications) return formatted_value_node
def format_to_fstring_transform(node): f_string_node = astroid.JoinedStr( lineno=node.lineno, col_offset=node.col_offset, parent=node.parent, ) formatted_value_node = astroid.FormattedValue( lineno=node.lineno, col_offset=node.col_offset, parent=node.parent, ) formatted_value_node.postinit(value=node.args[0]) # Removes the {} since it will be represented as # formatted_value_node string = astroid.Const(node.func.expr.value.replace('{}', '')) print node f_string_node.postinit(values=[string, formatted_value_node]) node.keywords = "a" return astroid.Const(node.func.expr.value.replace('{}', ''))
def convert_f_string_to_format_string(src: str) -> str: """ Convert a single f-string (passed as its source token) to a .format() call (as a source token). """ node = astroid.extract_node(src) # An f-string alternates between two kinds of nodes: string Const nodes and # FormattedValue nodes that hold the formatting bits format_string_parts = [] format_args = [] for child in node.get_children(): if isinstance(child, astroid.Const): format_string_parts.append(child.value) elif isinstance(child, astroid.FormattedValue): format_string_parts.append( "{{{c}{f}}}".format( c=CONVERSIONS[child.conversion], f=f":{child.format_spec.values[0].value}" if child.format_spec is not None else "", ) ) # We can pick the format value nodes right out of the string # and place them in the args; no need to introspect what they # actually are! format_args.append(child.value) format_string_node = astroid.Const("".join(format_string_parts)) format_call = astroid.Call(lineno=node.lineno, col_offset=node.col_offset) # The Call's func is a method looked up on the format string format_attr = astroid.Attribute(attrname="format", lineno=node.lineno, parent=format_call) format_attr.postinit(expr=format_string_node) # The Call's arguments are the format arguments extracted from the f-string format_call.postinit(func=format_attr, args=format_args, keywords=[]) return format_call.as_string()
def test_annotations_kwdefaults(self): ast_node = builder.extract_node(''' def test(a: 1, *args: 2, f:4='lala', **kwarg:3)->2: pass test.__annotations__ #@ test.__kwdefaults__ #@ ''') annotations = next(ast_node[0].infer()) self.assertIsInstance(annotations, astroid.Dict) self.assertIsInstance(annotations.getitem(astroid.Const('return')), astroid.Const) self.assertEqual(annotations.getitem(astroid.Const('return')).value, 2) self.assertIsInstance(annotations.getitem(astroid.Const('a')), astroid.Const) self.assertEqual(annotations.getitem(astroid.Const('a')).value, 1) self.assertEqual(annotations.getitem(astroid.Const('args')).value, 2) self.assertEqual(annotations.getitem(astroid.Const('kwarg')).value, 3) self.assertEqual(annotations.getitem(astroid.Const('f')).value, 4) kwdefaults = next(ast_node[1].infer()) self.assertIsInstance(kwdefaults, astroid.Dict)
def transform(self, node: ast.Call) -> ast.JoinedStr: f_string_node = ast.JoinedStr( lineno=node.lineno, col_offset=node.col_offset, parent=node.parent, ) constants: List[str] = re.split("{[^{]*}", node.func.expr.value) specs = re.findall("(?<={)[^{]*(?=})", node.func.expr.value) values = [] for i, const in enumerate(constants): values.append(ast.Const(const)) if i != len(constants) - 1: formatted_node = create_format_spec_node( node, node.args[i], specs[i]) values.append(formatted_node) f_string_node.postinit(values=values) return f_string_node
def test_annotations_kwdefaults(self): ast_node = builder.extract_node(""" def test(a: 1, *args: 2, f:4='lala', **kwarg:3)->2: pass test.__annotations__ #@ test.__kwdefaults__ #@ """) annotations = next(ast_node[0].infer()) self.assertIsInstance(annotations, astroid.Dict) self.assertIsInstance(annotations.getitem(astroid.Const("return")), astroid.Const) self.assertEqual(annotations.getitem(astroid.Const("return")).value, 2) self.assertIsInstance(annotations.getitem(astroid.Const("a")), astroid.Const) self.assertEqual(annotations.getitem(astroid.Const("a")).value, 1) self.assertEqual(annotations.getitem(astroid.Const("args")).value, 2) self.assertEqual(annotations.getitem(astroid.Const("kwarg")).value, 3) self.assertEqual(annotations.getitem(astroid.Const("f")).value, 4) kwdefaults = next(ast_node[1].infer()) self.assertIsInstance(kwdefaults, astroid.Dict)
def _check_new_format_specifiers(self, node, fields, named): """ Check attribute and index access in the format string ("{0.a}" and "{0[a]}"). """ for key, specifiers in fields: # Obtain the argument. If it can't be obtained # or inferred, skip this check. if key == "": # {[0]} will have an unnamed argument, defaulting # to 0. It will not be present in `named`, so use the value # 0 for it. key = 0 if isinstance(key, numbers.Number): try: argname = utils.get_argument_from_call(node, key) except utils.NoSuchArgumentError: continue else: if key not in named: continue argname = named[key] if argname in (astroid.Uninferable, None): continue try: argument = utils.safe_infer(argname) except astroid.InferenceError: continue if not specifiers or not argument: # No need to check this key if it doesn't # use attribute / item access continue if argument.parent and isinstance(argument.parent, astroid.Arguments): # Ignore any object coming from an argument, # because we can't infer its value properly. continue previous = argument parsed = [] for is_attribute, specifier in specifiers: if previous is astroid.Uninferable: break parsed.append((is_attribute, specifier)) if is_attribute: try: previous = previous.getattr(specifier)[0] except astroid.NotFoundError: if ( hasattr(previous, "has_dynamic_getattr") and previous.has_dynamic_getattr() ): # Don't warn if the object has a custom __getattr__ break path = get_access_path(key, parsed) self.add_message( "missing-format-attribute", args=(specifier, path), node=node, ) break else: warn_error = False if hasattr(previous, "getitem"): try: previous = previous.getitem(astroid.Const(specifier)) except ( astroid.AstroidIndexError, astroid.AstroidTypeError, astroid.AttributeInferenceError, ): warn_error = True except astroid.InferenceError: break if previous is astroid.Uninferable: break else: try: # Lookup __getitem__ in the current node, # but skip further checks, because we can't # retrieve the looked object previous.getattr("__getitem__") break except astroid.NotFoundError: warn_error = True if warn_error: path = get_access_path(key, parsed) self.add_message( "invalid-format-index", args=(specifier, path), node=node ) break try: previous = next(previous.infer()) except astroid.InferenceError: # can't check further if we can't infer it break
def infer_custom_name(node: astroid.Name, context=None): return iter((astroid.Const(value=variable2value(node.name)),))
def var_annotations_filter(node: nc.NodeNG) -> nc.NodeNG: """Filter annotated function variable assigns. This accounts for deferred evaluation. """ # pylint: disable=too-many-branches # pylint: disable=too-many-nested-blocks if using_future_annotations(node): # Future behavior: # Annotated assigns under functions are not evaluated. # Class and module vars are normally not either. However we # do evaluate if we come across an 'ioprepped' dataclass # decorator. (the 'ioprepped' decorator explicitly evaluates # dataclass annotations). fnode = node willeval = False while fnode is not None: if isinstance(fnode, astroid.ClassDef): if fnode.decorators is not None: found_ioprepped = False for dec in fnode.decorators.nodes: # Look for dataclassio.ioprepped. if (isinstance(dec, astroid.nodes.Attribute) and dec.attrname in {'ioprepped', 'will_ioprep'} and isinstance(dec.expr, astroid.nodes.Name) and dec.expr.name == 'dataclassio'): found_ioprepped = True break # Look for simply 'ioprepped'. if (isinstance(dec, astroid.nodes.Name) and dec.name in {'ioprepped', 'will_ioprep'}): found_ioprepped = True break if found_ioprepped: willeval = True break fnode = fnode.parent else: # Legacy behavior: # Annotated assigns under functions are not evaluated, # but class or module vars are. fnode = node willeval = True while fnode is not None: if isinstance(fnode, (astroid.FunctionDef, astroid.AsyncFunctionDef)): willeval = False break if isinstance(fnode, astroid.ClassDef): willeval = True break fnode = fnode.parent # If this annotation won't be eval'ed, replace it with a dummy string. if not willeval: dummyval = astroid.Const(parent=node, value='dummyval') node.annotation = dummyval return node
def const_node(draw, value=primitive_values): """Return a Const node with value drawn from <value>.""" return astroid.Const(draw(value))