davidhalter / jedi

Awesome autocompletion, static analysis and refactoring library for python
http://jedi.readthedocs.io
Other
5.73k stars 503 forks source link

How to discover the import statement for a particular Name? #1991

Closed misrasaurabh1 closed 2 months ago

misrasaurabh1 commented 2 months ago

I am trying to figure out the relevant import statement for a name with jedi. So for a = array([]) I would like to discover that it was imported as from numpy import array. For a = np.array([]), would like to discover the import statement import numpy as np.

goto and .infer tells us the module name and the full_name but I believe this is corresponding to the original module where it was discovered. The import asname might get missed.

I believe that during static analysis, jedi would discover the right import statement to traverse through. Is there a way I can find what import statements jedi discovered for a Name and use it?

davidhalter commented 2 months ago

If you use goto on np with follow_imports=False, that should actually work. Does that help?

misrasaurabh1 commented 2 months ago

Hi @davidhalter , thanks for the pointer. I tried your suggested method and it worked but at the same time jedi had trouble finding imports on the variety of cases I tried. The logic I tried was to filter that all the names coming after goto were 'modules'. I also filtered for the names being present in the same file. This worked a bit but for os.path.join it found os rather than os.path because os.path resolved to other module_path. In addition it missed cases like from numpy import array as n_array. Here n_array when used was discovered as a function rather than a module. Filtering on function logic led to discovering other functions defined in the same file. In addition, recreating the import statement wouldn't have been straightforward. Happy to share my test scripts if interested.

I am now planning to use libcst to discover the relevant imports. It seems powerful. https://libcst.readthedocs.io/en/latest/scope_tutorial.html

davidhalter commented 2 months ago

Hmmm why is numpy.array not a function?

os.path is a very very special case that resolves to different files depending on the operating system. The origin of os.path is also very weird in os.py if you look at the source.

I am aware of libcst. It used parso in earlier versions and has since created its own parser AFAIK. But I haven't followed it. If libcst is good enough for what you are trying to solve, then definitely use that. It is definitely a completely different level of abstraction and as long as you only work within one file it will probably work great for you. I think Jedi just is not the tool you are searching for. If you want to do fine grained logic within a file, Jedi is not a good tool. Jedi is useful for type inference and understanding bigger connections in your source code.

misrasaurabh1 commented 2 months ago

Thank you for your response! We use both jedi and libcst in our use case (building codeflash.ai). Jedi is our primary static analysis library for doing goto operations. We use libcst for parsing the code tree and modifying it. Interested to try out type inference with jedi, will play with it.