""" Tests for `api.names`. """ from textwrap import dedent def _assert_definition_names(definitions, names): assert [d.name for d in definitions] == names def _check_names(get_names, source, names): definitions = get_names(dedent(source)) _assert_definition_names(definitions, names) return definitions def test_get_definitions_flat(get_names): _check_names(get_names, """ import module class Class: pass def func(): pass data = None """, ['module', 'Class', 'func', 'data']) def test_dotted_assignment(get_names): _check_names(get_names, """ x = Class() x.y.z = None """, ['x', 'z']) # TODO is this behavior what we want? def test_multiple_assignment(get_names): _check_names(get_names, "x = y = None", ['x', 'y']) def test_multiple_imports(get_names): _check_names(get_names, """ from module import a, b from another_module import * """, ['a', 'b']) def test_nested_definitions(get_names): definitions = _check_names(get_names, """ class Class: def f(): pass def g(): pass """, ['Class']) subdefinitions = definitions[0].defined_names() _assert_definition_names(subdefinitions, ['f', 'g']) assert [d.full_name for d in subdefinitions] == ['__main__.Class.f', '__main__.Class.g'] def test_nested_class(get_names): definitions = _check_names(get_names, """ class L1: class L2: class L3: def f(): pass def f(): pass def f(): pass def f(): pass """, ['L1', 'f']) subdefs = definitions[0].defined_names() subsubdefs = subdefs[0].defined_names() _assert_definition_names(subdefs, ['L2', 'f']) _assert_definition_names(subsubdefs, ['L3', 'f']) _assert_definition_names(subsubdefs[0].defined_names(), ['f']) def test_class_fields_with_all_scopes_false(get_names): definitions = _check_names(get_names, """ from module import f g = f(f) class C: h = g def foo(x=a): bar = x return bar """, ['f', 'g', 'C', 'foo']) C_subdefs = definitions[-2].defined_names() foo_subdefs = definitions[-1].defined_names() _assert_definition_names(C_subdefs, ['h']) _assert_definition_names(foo_subdefs, ['x', 'bar']) def test_async_stmt_with_all_scopes_false(get_names): definitions = _check_names(get_names, """ from module import f import asyncio g = f(f) class C: h = g def __init__(self): pass async def __aenter__(self): pass def foo(x=a): bar = x return bar async def async_foo(duration): async def wait(): await asyncio.sleep(100) for i in range(duration//100): await wait() return duration//100*100 async with C() as cinst: d = cinst """, ['f', 'asyncio', 'g', 'C', 'foo', 'async_foo', 'cinst', 'd']) C_subdefs = definitions[3].defined_names() foo_subdefs = definitions[4].defined_names() async_foo_subdefs = definitions[5].defined_names() cinst_subdefs = definitions[6].defined_names() _assert_definition_names(C_subdefs, ['h', '__init__', '__aenter__']) _assert_definition_names(foo_subdefs, ['x', 'bar']) _assert_definition_names(async_foo_subdefs, ['duration', 'wait', 'i']) # We treat d as a name outside `async with` block _assert_definition_names(cinst_subdefs, []) def test_follow_imports(get_names): # github issue #344 imp = get_names('import datetime')[0] assert imp.name == 'datetime' datetime_names = [str(d.name) for d in imp.defined_names()] assert 'timedelta' in datetime_names def test_names_twice(get_names): code = dedent(''' def lol(): pass ''') defs = get_names(code) assert defs[0].defined_names() == [] def test_simple_name(get_names): defs = get_names('foo', references=True) assert not defs[0]._name.infer() def test_no_error(get_names): code = dedent(""" def foo(a, b): if a == 10: if b is None: print("foo") a = 20 """) func_name, = get_names(code) a, b, a20 = func_name.defined_names() assert a.name == 'a' assert b.name == 'b' assert a20.name == 'a' assert a20.goto() == [a20]