Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to check does a file imports from another file in Python

Tags:

python

import

Suppose i have a project structure like this

src
└── app
    ├── main.py
    ├── db
    │   └── database.py
    ├── models
    │   ├── model_a.py
    │   └── model_b.py
    └── tests
        ├── test_x.py
        └── test_y.py

I want to check which file uses a class or a function from another file. I have a class called Test in main.py

class Test:
    pass

I used that class in model_a,

from ..main import Test

But in model_b i used

from ..main import Test
from ..db.database import Data

I want to to check which file uses another file, just like tree command, just a folder name is enough so i tried an old method but it was inefficient ,dirty and that was not something that i expect. The method was i created a file in src named check.py, i imported all packages

from app.db import database
from app.models import model_a, model_b
from app.tests import test_x, test_y
from app import main 

print('__file__={0:<35} | __name__={1:<20} | __package__={2:<20}'.format(__file__,__name__,str(__package__)))

And i added this line in the bottom of all files

print('__file__={0:<35} | __name__={1:<20} | __package__={2:<20}'.format(__file__,__name__,str(__package__)))

So when i run check.py i get this result

__file__=/home/yagiz/Desktop/struct/src/app/main.py | __name__=app.main             | __package__=app                 
__file__=/home/yagiz/Desktop/struct/src/app/db/database.py | __name__=app.db.database      | __package__=app.db              
__file__=/home/yagiz/Desktop/struct/src/app/models/model_a.py | __name__=app.models.model_a   | __package__=app.models          
__file__=/home/yagiz/Desktop/struct/src/app/models/model_b.py | __name__=app.models.model_b   | __package__=app.models          
__file__=/home/yagiz/Desktop/struct/src/app/tests/test_x.py | __name__=app.tests.test_x     | __package__=app.tests           
__file__=/home/yagiz/Desktop/struct/src/app/tests/test_y.py | __name__=app.tests.test_y     | __package__=app.tests           
__file__=/home/yagiz/Desktop/struct/src/check.py | __name__=__main__             | __package__=None   

The result is dirty and doesn't meet my expectations is there a way to get a output like this?

main.py = app/models/model_a, app/models/model_b   # These files imports something from main.py
models_b = None                                    # No file imports from models_b

Update, i tried @Hessam Korki's suggestion it doesn't works.

I looked up the source code of modulefinder and i found it adds a badmodule in every import statement which is not useful for me.

Here is how did it go, first i created a function, also i created an another project structure.

src
├── empty.py
├── __init__.py
├── main.py
├── module_finder.py
├── other
│   └── other.py
├── test
│   └── some_app.py
└── this_imports.py

Here is the module_finder.py that contains my function

from modulefinder import ModuleFinder
file_names = ["this_imports.py", "main.py", "test/some_app.py", "other/other.py", "empty.py"]

def check_imports(file_names):
    finder = ModuleFinder()
    for file in file_names:
        finder.run_script(file)
        print("\n", file)
        for name, mod in finder.modules.items():
            print('%s: ' % name, end='')
            print(','.join(list(mod.globalnames.keys())[:3]))

            print('\n'.join(finder.badmodules.keys()))

Empty file is empty(as expected), in main.py i have

class Test:
    pass

In this_imports.py i only have

from src.main import Test

In other/other.py i have

from src.main import Test 
from src.test import DifferentTest

And for the last one in test/some_app.py i have

from src.main import Test

class DifferentTest:
    pass

So the result should be:

empty.py = None
main.py = None
other/other.py = src.main , src.test
test/some_app.py = src.main
this_imports.py = src.main 

But the function gives a wrong result, here is the output:

 Filename:  this_imports.py
__main__: Test
src.main

 Filename:  main.py
__main__: Test,__module__,__qualname__
src.main

 Filename:  test/some_app.py
__main__: Test,__module__,__qualname__
src.main

 Filename:  other/other.py
__main__: Test,__module__,__qualname__
src.main
src.test

 Filename:  empty.py
__main__: Test,__module__,__qualname__
src.main
src.test
like image 984
Yagiz Degirmenci Avatar asked Aug 04 '20 13:08

Yagiz Degirmenci


People also ask

How does Python find imports?

Step 2: If the module that needs to be imported is not found in the current directory. Then python will search it in the PYTHONPATH which is a list of directory names, with the same syntax as the shell variable PATH. To know the directories in PYTHONPATH we can simply get them by the sys module.

What does __ init __ py do in Python?

The __init__.py files are required to make Python treat directories containing the file as packages. This prevents directories with a common name, such as string , unintentionally hiding valid modules that occur later on the module search path.


1 Answers

I believe python's Modulefinder will effectively solve your problem. There is a key named '__main__' in the Modulefinder().items() which holds the modules that were imported in a python file. After running the script through your project and storing the data in a way that suits your purpose, you should be good to go

like image 181
Hesam Korki Avatar answered Oct 07 '22 00:10

Hesam Korki