def test_rename_reads_name(self): src = 'aaa.bbb()' t = pasta.ast_parse(src, py_ver) sc = scope.analyze(t, py_ver) self.assertTrue(rename._rename_reads(sc, t, 'aaa', 'xxx', py_ver)) self.checkAstsEqual(t, pasta.ast_parse('xxx.bbb()', py_ver), py_ver)
def test_rename_reads_noop(self): src = 'aaa.bbb.ccc()' t = pasta.ast_parse(src, py_ver) sc = scope.analyze(t, py_ver) rename._rename_reads(sc, t, 'aaa.bbb.ccc.ddd', 'xxx.yyy', py_ver) rename._rename_reads(sc, t, 'bbb.aaa', 'xxx.yyy', py_ver) self.checkAstsEqual(t, pasta.ast_parse(src, py_ver), py_ver)
def test_rename_reads_attribute(self): src = 'aaa.bbb.ccc()' t = pasta.ast_parse(src, py_ver) sc = scope.analyze(t, py_ver) rename._rename_reads(sc, t, 'aaa.bbb', 'xxx.yyy', py_ver) self.checkAstsEqual(t, pasta.ast_parse('xxx.yyy.ccc()', py_ver), py_ver)
def _is_syntax_valid(filepath, py_ver): with io.open(filepath, 'r', encoding='UTF-8') as f: try: pasta.ast_parse(f.read(), py_ver) except SyntaxError: return False return True
def test_rename_external_in_import_multiple_aliases(self): src = 'import aaa, aaa.bbb, aaa.bbb.ccc' t = pasta.ast_parse(src, py_ver) self.assertTrue( rename.rename_external(t, 'aaa.bbb', 'xxx.yyy', py_ver)) self.checkAstsEqual( t, pasta.ast_parse('import aaa, xxx.yyy, xxx.yyy.ccc', py_ver), py_ver)
def test_rename_external_in_importfrom_alias(self): src = 'from aaa.bbb import ccc\nccc.foo()' t = pasta.ast_parse(src, py_ver) self.assertTrue( rename.rename_external(t, 'aaa.bbb.ccc', 'xxx.yyy', py_ver)) self.checkAstsEqual( t, pasta.ast_parse('from xxx import yyy\nyyy.foo()', py_ver), py_ver)
def test_rename_external_in_import_with_asname(self): src = 'import aaa.bbb.ccc as ddd\nddd.foo()' t = pasta.ast_parse(src, py_ver) self.assertTrue( rename.rename_external(t, 'aaa.bbb', 'xxx.yyy', py_ver)) self.checkAstsEqual( t, pasta.ast_parse('import xxx.yyy.ccc as ddd\nddd.foo()', py_ver), py_ver)
def test_inline_multiple_reads(self): src = textwrap.dedent("""\ CONSTANT = "foo" def a(b=CONSTANT): return b == CONSTANT """) expected = textwrap.dedent("""\ def a(b="foo"): return b == "foo" """) t = pasta.ast_parse(src, py_ver) inline.inline_name(t, 'CONSTANT', py_ver=py_ver) self.checkAstsEqual(t, pasta.ast_parse(expected, py_ver), py_ver)
def test_add_existing_import_normal_import(self): tree = pasta.ast_parse('import a.b.c', py_ver) self.assertEqual( 'a.b', import_utils.add_import(tree, 'a.b', py_ver, from_import=False)) self.assertEqual('import a.b.c\n', pasta.dump(tree, py_ver))
def test_add_existing_import_aliased_with_asname(self): tree = pasta.ast_parse('from a.b import c as d', py_ver) self.assertEqual( 'd', import_utils.add_import(tree, 'a.b.c', py_ver, asname='e')) self.assertEqual('from a.b import c as d\n', pasta.dump(tree, py_ver))
def _is_syntax_valid(filepath, py_ver): with open(filepath, 'r') as f: try: t = pasta.ast_parse(f.read(), py_ver) except SyntaxError: return False return True
def _rename_reads(sc, t, old_name, new_name, py_ver=sys.version_info[:2]): """Updates all locations in the module where the given name is read. Arguments: sc: (scope.Scope) Scope to work in. This should be the scope of `t`. t: (ast.AST) The AST to perform updates in. old_name: (string) Dotted name to update. new_name: (string) Dotted name to replace it with. Returns: True if any changes were made, False otherwise. """ name_parts = old_name.split('.') try: name = sc.names[name_parts[0]] for part in name_parts[1:]: name = name.attrs[part] except KeyError: return False has_changed = False for ref_node in name.reads: if isinstance( ref_node, (ast27.Name, ast3.Name, ast27.Attribute, ast3.Attribute)): ast_utils.replace_child( sc.parent(ref_node), ref_node, pasta.ast_parse(new_name, py_ver).body[0].value) has_changed = True elif isinstance(ref_node, ast.Str) and ref_node.s.startswith(old_name): ref_node.s = ref_node.s.replace(old_name, new_name, 1) return has_changed
def test_try_nested_imports(self): source = textwrap.dedent("""\ try: import aaa except: import bbb finally: import ccc """) tree = pasta.ast_parse(source, py_ver) nodes = tree.body node_aaa, node_bbb, node_ccc = ast_utils.find_nodes_by_type( tree, pasta.ast(py_ver).alias, py_ver) s = scope.analyze(tree, py_ver) self.assertItemsEqual(s.names.keys(), {'aaa', 'bbb', 'ccc'}) self.assertItemsEqual(s.external_references.keys(), {'aaa', 'bbb', 'ccc'}) self.assertEqual(s.names['aaa'].definition, node_aaa) self.assertEqual(s.names['bbb'].definition, node_bbb) self.assertEqual(s.names['ccc'].definition, node_ccc) for ref in {'aaa', 'bbb', 'ccc'}: self.assertEqual(s.names[ref].reads, [], 'Expected no reads for %s' % ref)
def test_inline_non_assign_fails(self): src = 'CONSTANT1, CONSTANT2 = values' t = pasta.ast_parse(src, py_ver) with self.assertRaisesRegexp( inline.InlineError, '\'CONSTANT1\' is not declared in an assignment'): inline.inline_name(t, 'CONSTANT1', py_ver=py_ver)
def test_import_attribute_references(self): source = textwrap.dedent("""\ import aaa.bbb.ccc, ddd.eee aaa.x() aaa.bbb.y() aaa.bbb.ccc.z() """) tree = pasta.ast_parse(source, py_ver) nodes = tree.body call1 = nodes[1].value.func.value call2 = nodes[2].value.func.value call3 = nodes[3].value.func.value s = scope.analyze(tree, py_ver) self.assertItemsEqual(s.names.keys(), {'aaa', 'ddd'}) self.assertItemsEqual(s.external_references.keys(), {'aaa', 'aaa.bbb', 'aaa.bbb.ccc', 'ddd', 'ddd.eee'}) self.assertItemsEqual(s.names['aaa'].reads, [call1, call2.value, call3.value.value]) self.assertItemsEqual(s.names['aaa'].attrs['bbb'].reads, [call2, call3.value]) self.assertItemsEqual(s.names['aaa'].attrs['bbb'].attrs['ccc'].reads, [call3])
def test_remove_duplicates_normal_and_from(self): src = """ import a.b from a import b """ tree = pasta.ast_parse(src, py_ver) self.assertFalse(import_utils.remove_duplicates(tree, py_ver)) self.assertEqual(len(tree.body), 2)
def test_add_from_import(self): tree = pasta.ast_parse('', py_ver) self.assertEqual( 'c', import_utils.add_import(tree, 'a.b.c', py_ver, from_import=True)) self.assertEqual('from a.b import c\n', pasta.dump(tree, py_ver))
def test_import_from_alias(self): src = """\ from my_module import a, b b.foo() """ tree = pasta.ast_parse(src, py_ver) self.assertItemsEqual( import_utils.get_unused_import_aliases(tree, py_ver), [tree.body[0].names[0]])
def test_normal_imports(self): src = """\ import a import b a.foo() """ tree = pasta.ast_parse(src, py_ver) self.assertItemsEqual( import_utils.get_unused_import_aliases(tree, py_ver), [tree.body[1].names[0]])
def test_add_normal_import_with_asname(self): tree = pasta.ast_parse('', py_ver) self.assertEqual( 'd', import_utils.add_import(tree, 'a.b.c', py_ver, asname='d', from_import=False)) self.assertEqual('import a.b.c as d\n', pasta.dump(tree, py_ver))
def test_remove_full_importfrom(self): src = 'from m import a' tree = pasta.ast_parse(src, py_ver) sc = scope.analyze(tree, py_ver) a_node = tree.body[0].names[0] import_utils.remove_import_alias_node(sc, a_node, py_ver=py_ver) self.assertEqual(len(tree.body), 0)
def test_add_import_with_conflict(self): tree = pasta.ast_parse('def c(): pass\n', py_ver) self.assertEqual( 'c_1', import_utils.add_import(tree, 'a.b.c', py_ver, from_import=True)) self.assertEqual('from a.b import c as c_1\ndef c():\n pass\n', pasta.dump(tree, py_ver))
def test_inline_function_fails(self): src = 'def func(): pass\nfunc()\n' t = pasta.ast_parse(src, py_ver) with self.assertRaisesRegexp( inline.InlineError, '\'func\' is not a constant; it has type %r' % (ast27.FunctionDef if py_ver == 'PY27' else ast3.FunctionDef, )): inline.inline_name(t, 'func', py_ver=py_ver)
def test_inline_non_constant_fails(self): src = textwrap.dedent("""\ NOT_A_CONSTANT = "foo" NOT_A_CONSTANT += "bar" """) t = pasta.ast_parse(src, py_ver) with self.assertRaisesRegexp( inline.InlineError, '\'NOT_A_CONSTANT\' is not a constant'): inline.inline_name(t, 'NOT_A_CONSTANT', py_ver=py_ver)
def test_add_single_name_from_import_with_asname(self): tree = pasta.ast_parse('', py_ver) self.assertEqual( 'bar', import_utils.add_import(tree, 'foo', py_ver, asname='bar', from_import=True)) self.assertEqual('import foo as bar\n', pasta.dump(tree, py_ver))
def test_import_asname(self): src = """\ from my_module import a as a_mod, b as unused_b_mod import c as c_mod, d as unused_d_mod a_mod.foo() c_mod.foo() """ tree = pasta.ast_parse(src, py_ver) self.assertItemsEqual( import_utils.get_unused_import_aliases(tree, py_ver), [tree.body[0].names[1], tree.body[1].names[1]])
def test_dynamic_import(self): # For now we just don't want to error out on these, longer # term we want to do the right thing (see # https://github.com/google/pasta/issues/32) src = """\ def foo(): import bar """ tree = pasta.ast_parse(src, py_ver) self.assertItemsEqual( import_utils.get_unused_import_aliases(tree, py_ver), [])
def test_split_imports_with_alias(self): src = 'import aaa as a, bbb as b, ccc as c\n' t = pasta.ast_parse(src, py_ver) import_node = t.body[0] sc = scope.analyze(t, py_ver) import_utils.split_import(sc, import_node, import_node.names[1]) self.assertEqual(2, len(t.body)) self.assertEqual([alias.name for alias in t.body[0].names], ['aaa', 'ccc']) self.assertEqual([alias.name for alias in t.body[1].names], ['bbb']) self.assertEqual(t.body[1].names[0].asname, 'b')
def test_split_from_import(self): src = 'from aaa import bbb, ccc, ddd\n' t = pasta.ast_parse(src, py_ver) import_node = t.body[0] sc = scope.analyze(t, py_ver) import_utils.split_import(sc, import_node, import_node.names[1]) self.assertEqual(2, len(t.body)) self.assertEqual(pasta.ast(py_ver).ImportFrom, type(t.body[1])) self.assertEqual(t.body[0].module, 'aaa') self.assertEqual(t.body[1].module, 'aaa') self.assertEqual([alias.name for alias in t.body[0].names], ['bbb', 'ddd'])
def test_remove_duplicates_aliases(self): src = """ import a import a as ax import a as ax2 import a as ax """ tree = pasta.ast_parse(src, py_ver) self.assertTrue(import_utils.remove_duplicates(tree, py_ver)) self.assertEqual(len(tree.body), 3) self.assertEqual(tree.body[0].names[0].asname, None) self.assertEqual(tree.body[1].names[0].asname, 'ax') self.assertEqual(tree.body[2].names[0].asname, 'ax2')