def test_variable(self): expected = definitions.Variable(name="x", source="", lineno=1, col_offset=0) actual = utils.var_from_source("x") self.assertEqual(expected, actual)
def visit_alias(self, node: ast3.alias): # Aliases are the "name as other_name" in "import name as other_name". return definitions.Variable( name=node.asname if node.asname else node.name, source=self._source, # These must be filled in later. lineno=-1, col_offset=-1)
def visit_Attribute(self, node: ast3.Attribute): # If this Attribute isn't being used on the left-hand side of an assignment # statement, the visitor doesn't need to save it. if not self._is_store(node): return if self._in_class: # If in a class, only save "self.attr" expressions. if isinstance(node.value, ast3.Name) and node.value.id == "self": self._namespace[node.attr].append( definitions.Variable(name=node.attr, source=self._source, lineno=node.lineno, col_offset=node.col_offset)) else: # Outside of a class, an expression like "a.b.c" is stored as # Variable(name = "a"). When parsed, "a.b.c" becomes # Attribute(Attribute(Name("a"), "b"), "c"). Since only "a" needs to be # saved, proceed with the visit as normal so visit_Name handles "a". # However, "a" and "b" are considered Loads, not Stores, so we need to # update the node. node.value.ctx = ast3.Store() self.generic_visit(node)
def test_class_members(self): # Classes are generated by the DefinitionFinder visitor passing in the # class def, the list of methods, the list of fields and any nested classes. # This test represents this by generating each piece separately. class_stmt = textwrap.dedent("""\ class A: class_field = 3 def __init__(self, arg): self.instance_field = arg def a_method(self, arg): return self.instance_field + arg class _simple_nested_cls: pass """) expected_methods = { "__init__": utils.make_func(name="__init__", lineno=3, col_offset=2, params=[ utils.make_arg("self", lineno=3, col_offset=15), utils.make_arg("arg", lineno=3, col_offset=21) ]), "a_method": utils.make_func(name="a_method", lineno=5, col_offset=2, params=[ utils.make_arg("self", lineno=5, col_offset=15), utils.make_arg("arg", lineno=5, col_offset=21) ]), } expected_fields = { "class_field": definitions.Variable("class_field", source="", lineno=2, col_offset=2), "instance_field": definitions.Variable("instance_field", source="", lineno=4, col_offset=4) } expected_nests = { "_simple_nested_cls": definitions.Class(name="_simple_nested_cls", source="", lineno=7, col_offset=2, bases=[], keyword_bases=[], decorators=[], fields={}, methods={}, nested_classes={}) } expected_class = definitions.Class(name="A", source="", lineno=1, col_offset=0, bases=[], keyword_bases=[], decorators=[], fields=expected_fields, methods=expected_methods, nested_classes=expected_nests) # We have to pull apart the parsed class by hand. node = utils.parse_stmt(class_stmt) classfield, init, method, nested = node.body # init.body[0] is an ast3.Attribute, and for class fields, there needs to # be a definition for the attr instead of the value. So the Variable # definition isn't created with from_node, because attr is a str. instance_field = init.body[0].targets[0] actual_fields = { "class_field": definitions.Variable.from_node(classfield.targets[0]), "instance_field": definitions.Variable(instance_field.attr, "", instance_field.lineno, instance_field.col_offset), } actual_methods = { "__init__": definitions.Function.from_node(init), "a_method": definitions.Function.from_node(method), } actual_nests = { "_simple_nested_cls": definitions.Class.from_node(nested, {}, {}, {}), } actual_class = definitions.Class.from_node(node, actual_fields, actual_methods, actual_nests) self.assertEqual(expected_class, actual_class)