@@ -215,6 +215,204 @@ def func_1():
215215 assert call_site .file == consumer_file
216216
217217
218+ def test_import_resolution_init_wildcard (tmpdir : str ) -> None :
219+ """Tests that named import from a file with wildcard resolves properly"""
220+ # language=python
221+ content1 = """TEST_CONST=2
222+ foo=9
223+ """
224+ content2 = """from testdir.test1 import *
225+ bar=foo
226+ test=TEST_CONST"""
227+ content3 = """from testdir import TEST_CONST
228+ test3=TEST_CONST"""
229+ with get_codebase_session (tmpdir = tmpdir , files = {"testdir/test1.py" : content1 , "testdir/__init__.py" : content2 , "test3.py" : content3 }) as codebase :
230+ file1 : SourceFile = codebase .get_file ("testdir/test1.py" )
231+ file2 : SourceFile = codebase .get_file ("testdir/__init__.py" )
232+ file3 : SourceFile = codebase .get_file ("test3.py" )
233+
234+ symb = file1 .get_symbol ("TEST_CONST" )
235+ test = file2 .get_symbol ("test" )
236+ test3 = file3 .get_symbol ("test3" )
237+ test3_import = file3 .get_import ("TEST_CONST" )
238+
239+ assert len (symb .usages ) == 3
240+ assert symb .symbol_usages == [test , test3 , test3_import ]
241+
242+
243+ def test_import_resolution_wildcard_func (tmpdir : str ) -> None :
244+ """Tests that named import from a file with wildcard resolves properly"""
245+ # language=python
246+ content1 = """
247+ def foo():
248+ pass
249+ def bar():
250+ pass
251+ """
252+ content2 = """
253+ from testa import *
254+
255+ foo()
256+ """
257+
258+ with get_codebase_session (tmpdir = tmpdir , files = {"testa.py" : content1 , "testb.py" : content2 }) as codebase :
259+ testa : SourceFile = codebase .get_file ("testa.py" )
260+ testb : SourceFile = codebase .get_file ("testb.py" )
261+
262+ foo = testa .get_symbol ("foo" )
263+ bar = testa .get_symbol ("bar" )
264+ assert len (foo .usages ) == 1
265+ assert len (foo .call_sites ) == 1
266+
267+ assert len (bar .usages ) == 0
268+ assert len (bar .call_sites ) == 0
269+ assert len (testb .function_calls ) == 1
270+
271+
272+ def test_import_resolution_chaining_wildcards (tmpdir : str ) -> None :
273+ """Tests that chaining wildcard imports resolves properly"""
274+ # language=python
275+ content1 = """TEST_CONST=2
276+ foo=9
277+ """
278+ content2 = """from testdir.test1 import *
279+ bar=foo
280+ test=TEST_CONST"""
281+ content3 = """from testdir import *
282+ test3=TEST_CONST"""
283+ with get_codebase_session (tmpdir = tmpdir , files = {"testdir/test1.py" : content1 , "testdir/__init__.py" : content2 , "test3.py" : content3 }) as codebase :
284+ file1 : SourceFile = codebase .get_file ("testdir/test1.py" )
285+ file2 : SourceFile = codebase .get_file ("testdir/__init__.py" )
286+ file3 : SourceFile = codebase .get_file ("test3.py" )
287+
288+ symb = file1 .get_symbol ("TEST_CONST" )
289+ test = file2 .get_symbol ("test" )
290+ bar = file2 .get_symbol ("bar" )
291+ mid_import = file2 .get_import ("testdir.test1" )
292+ test3 = file3 .get_symbol ("test3" )
293+
294+ assert len (symb .usages ) == 2
295+ assert symb .symbol_usages == [test , test3 ]
296+ assert mid_import .symbol_usages == [test , bar , test3 ]
297+
298+
299+ def test_import_resolution_init_deep_nested_wildcards (tmpdir : str ) -> None :
300+ """Tests that chaining wildcard imports resolves properly"""
301+ # language=python
302+
303+ files = {
304+ "test/nest/nest2/test1.py" : """test_const=5
305+ test_not_used=2
306+ test_used_parent=5
307+ """ ,
308+ "test/nest/nest2/__init__.py" : """from .test1 import *
309+ t1=test_used_parent
310+ """ ,
311+ "test/nest/__init__.py" : """from .nest2 import *""" ,
312+ "test/__init__.py" : """from .nest import *""" ,
313+ "main.py" : """
314+ from test import *
315+ main_test=test_const
316+ """ ,
317+ }
318+ with get_codebase_session (tmpdir = tmpdir , files = files ) as codebase :
319+ deepest_layer : SourceFile = codebase .get_file ("test/nest/nest2/test1.py" )
320+ main : SourceFile = codebase .get_file ("main.py" )
321+ parent_file : SourceFile = codebase .get_file ("test/nest/nest2/__init__.py" )
322+
323+ main_test = main .get_symbol ("main_test" )
324+ t1 = parent_file .get_symbol ("t1" )
325+ test_const = deepest_layer .get_symbol ("test_const" )
326+ test_not_used = deepest_layer .get_symbol ("test_not_used" )
327+ test_used_parent = deepest_layer .get_symbol ("test_used_parent" )
328+
329+ assert len (test_const .usages ) == 1
330+ assert test_const .usages [0 ].usage_symbol == main_test
331+ assert len (test_not_used .usages ) == 0
332+ assert len (test_used_parent .usages ) == 1
333+ assert test_used_parent .usages [0 ].usage_symbol == t1
334+
335+
336+ def test_import_resolution_chaining_many_wildcards (tmpdir : str ) -> None :
337+ """Tests that chaining wildcard imports resolves properly"""
338+ # language=python
339+
340+ files = {
341+ "test1.py" : """
342+ test_const=5
343+ test_not_used=2
344+ test_used_parent=5
345+ """ ,
346+ "test2.py" : """from test1 import *
347+ t1=test_used_parent
348+ """ ,
349+ "test3.py" : """from test2 import *""" ,
350+ "test4.py" : """from test3 import *""" ,
351+ "main.py" : """
352+ from test4 import *
353+ main_test=test_const
354+ """ ,
355+ }
356+ with get_codebase_session (tmpdir = tmpdir , files = files ) as codebase :
357+ furthest_layer : SourceFile = codebase .get_file ("test1.py" )
358+ main : SourceFile = codebase .get_file ("main.py" )
359+ parent_file : SourceFile = codebase .get_file ("test2.py" )
360+
361+ main_test = main .get_symbol ("main_test" )
362+ t1 = parent_file .get_symbol ("t1" )
363+ test_const = furthest_layer .get_symbol ("test_const" )
364+ test_not_used = furthest_layer .get_symbol ("test_not_used" )
365+ test_used_parent = furthest_layer .get_symbol ("test_used_parent" )
366+
367+ assert len (test_const .usages ) == 1
368+ assert test_const .usages [0 ].usage_symbol == main_test
369+ assert len (test_not_used .usages ) == 0
370+ assert len (test_used_parent .usages ) == 1
371+ assert test_used_parent .usages [0 ].usage_symbol == t1
372+
373+
374+ def test_import_resolution_init_deep_nested_wildcards_named (tmpdir : str ) -> None :
375+ """Tests that chaining wildcard imports resolves properly"""
376+ # language=python
377+
378+ files = {
379+ "test/nest/nest2/test1.py" : """test_const=5
380+ test_not_used=2
381+ test_used_parent=5
382+ """ ,
383+ "test/nest/nest2/__init__.py" : """from .test1 import *
384+ t1=test_used_parent
385+ """ ,
386+ "test/nest/__init__.py" : """from .nest2 import *""" ,
387+ "test/__init__.py" : """from .nest import *""" ,
388+ "main.py" : """
389+ from test import test_const
390+ main_test=test_const
391+ """ ,
392+ }
393+ with get_codebase_session (tmpdir = tmpdir , files = files ) as codebase :
394+ deepest_layer : SourceFile = codebase .get_file ("test/nest/nest2/test1.py" )
395+ main : SourceFile = codebase .get_file ("main.py" )
396+ parent_file : SourceFile = codebase .get_file ("test/nest/nest2/__init__.py" )
397+ test_nest : SourceFile = codebase .get_file ("test/__init__.py" )
398+
399+ main_test = main .get_symbol ("main_test" )
400+ t1 = parent_file .get_symbol ("t1" )
401+ test_const = deepest_layer .get_symbol ("test_const" )
402+ test_not_used = deepest_layer .get_symbol ("test_not_used" )
403+ test_used_parent = deepest_layer .get_symbol ("test_used_parent" )
404+
405+ test_const_imp = main .get_import ("test_const" )
406+
407+ assert len (test_const .usages ) == 2
408+ assert test_const .usages [0 ].usage_symbol == main_test
409+ assert test_const .usages [1 ].usage_symbol == test_const_imp
410+
411+ assert len (test_not_used .usages ) == 0
412+ assert len (test_used_parent .usages ) == 1
413+ assert test_used_parent .usages [0 ].usage_symbol == t1
414+
415+
218416def test_import_resolution_circular (tmpdir : str ) -> None :
219417 """Tests function.usages returns usages from file imports"""
220418 # language=python
@@ -367,4 +565,66 @@ def test_import_wildcard_preserves_import_resolution(tmpdir: str) -> None:
367565 ) as codebase :
368566 mainfile : SourceFile = codebase .get_file ("file.py" )
369567
370- assert len (mainfile .ctx .edges ) == 5
568+ assert len (mainfile .ctx .edges ) == 10
569+
570+
571+ def test_import_resolution_init_wildcard_no_dupe (tmpdir : str ) -> None :
572+ """Tests that named import from a file with wildcard resolves properly and doesn't
573+ result in duplicate usages
574+ """
575+ # language=python
576+ content1 = """TEST_CONST=2
577+ foo=9
578+ """
579+ content2 = """from testdir.test1 import *
580+ bar=foo
581+ test=TEST_CONST"""
582+ content3 = """from testdir import TEST_CONST
583+ test3=TEST_CONST"""
584+ content4 = """from testdir import foo
585+ test4=foo"""
586+ with get_codebase_session (tmpdir = tmpdir , files = {"testdir/test1.py" : content1 , "testdir/__init__.py" : content2 , "test3.py" : content3 , "test4.py" : content4 }) as codebase :
587+ file1 : SourceFile = codebase .get_file ("testdir/test1.py" )
588+ file2 : SourceFile = codebase .get_file ("testdir/__init__.py" )
589+ file3 : SourceFile = codebase .get_file ("test3.py" )
590+
591+ symb = file1 .get_symbol ("TEST_CONST" )
592+ test = file2 .get_symbol ("test" )
593+ test3 = file3 .get_symbol ("test3" )
594+ test3_import = file3 .get_import ("TEST_CONST" )
595+
596+ assert len (symb .usages ) == 3
597+ assert symb .symbol_usages == [test , test3 , test3_import ]
598+
599+
600+ def test_import_resolution_init_wildcard_chainging_deep (tmpdir : str ) -> None :
601+ """Tests that named import from a file with wildcard resolves properly and doesn't
602+ result in duplicate usages
603+ """
604+ # language=python
605+ content1 = """TEST_CONST=2
606+ """
607+ content2 = """from .file1 import *"""
608+ content3 = """from .dir import *"""
609+ content4 = """from .dir import TEST_CONST
610+ test1=TEST_CONST"""
611+ with get_codebase_session (
612+ tmpdir = tmpdir ,
613+ files = {
614+ "dir/dir/dir/dir/file1.py" : content1 ,
615+ "dir/dir/dir/dir/__init__.py" : content2 ,
616+ "dir/dir/dir/__init__.py" : content3 ,
617+ "dir/dir/__init__.py" : content3 ,
618+ "dir/__init__.py" : content3 ,
619+ "file2.py" : content4 ,
620+ },
621+ ) as codebase :
622+ file1 : SourceFile = codebase .get_file ("dir/dir/dir/dir/file1.py" )
623+ file2 : SourceFile = codebase .get_file ("file2.py" )
624+
625+ symb = file1 .get_symbol ("TEST_CONST" )
626+ test1 = file2 .get_symbol ("test1" )
627+ imp = file2 .get_import ("TEST_CONST" )
628+
629+ assert len (symb .usages ) == 2
630+ assert symb .symbol_usages == [test1 , imp ]
0 commit comments