Analyse internal package imports in a given path with
.py
files
- Dependents of x = Modules that import in x
- Dependencies of x = Modules that x imports
Columns
- 'Dependents' (of module m in row x) = number of modules that import in m
- 'Dependencies' (of module m in row x) = number of modules that m imports
- 'Score' = 'Dependents' column minus 'Dependencies' column
- 'Proportion' = 'Dependents' column / ('Dependents' column + 'Dependencies' column) * 100
What does the numbers mean?
- A larger score means it is a dependency of other modules more
- "A dependency of a lot of modules"
- A smaller score means it depends on other modules more
- "Depends on a lot of modules"
- Note that a negative score doesn't mean it's "bad". It is good to split up your code into modules where they logically fit.
- A high proportion means most connections to other modules are its dependents
- A low proportion means most connections to other modules are its dependencies
Example output for koneko, using panda's to_markdown()
method
Dependents | Dependencies | Score | Proportion | |
---|---|---|---|---|
pure.py | 10 | 0 | 10 | 100 |
colors.py | 2 | 0 | 2 | 100 |
__init__.py | 14 | 0 | 14 | 100 |
files.py | 5 | 1 | 4 | 83 |
printer.py | 7 | 2 | 5 | 78 |
utils.py | 9 | 3 | 6 | 75 |
config.py | 5 | 2 | 3 | 71 |
lscat.py | 6 | 4 | 2 | 60 |
api.py | 3 | 3 | 0 | 50 |
cli.py | 2 | 3 | -1 | 40 |
prompt.py | 3 | 5 | -2 | 38 |
picker.py | 3 | 5 | -2 | 38 |
data.py | 1 | 2 | -1 | 33 |
screens.py | 2 | 4 | -2 | 33 |
download.py | 2 | 4 | -2 | 33 |
lscat_prompt.py | 1 | 3 | -2 | 25 |
assistants.py | 2 | 7 | -5 | 22 |
main.py | 2 | 7 | -5 | 22 |
ui.py | 2 | 12 | -10 | 14 |
lscat_app.py | 1 | 7 | -6 | 12 |
__main__.py | 0 | 5 | -5 | 0 |
Look at this graph generated by pyreverse
:
How can we decipher this mess? Well, every box/module has connections to and/or from other modules. Modules with lots of arrows pointing to its box is highly dependent on, while those with lines but no arrows mean it imports in things from smaller modules (functional core) and construct something bigger and complex, probably the entry point to the program (hint hint, the imperative shell).
git clone https://github.com/twenty5151/import-analyzer
cd import-analyzer
pip install -r requirements.txt
python imports.py -p {PATH_TO_FILES} -n {NAME_OF_PACKAGE}
- PATH_TO_FILES: the directory where your
.py
files are - NAME_OF_PACKAGE: usually the name of the above directory. Only the internal imports of your modules are analyzed, see
from {NAME_OF_PACKAGE} import ...
- Optional argument:
-i {INIT_FILE}
- INIT_FILE: the name of your init file, where constants are stored. Default is
__init__.py
- INIT_FILE: the name of your init file, where constants are stored. Default is
- PATH_TO_FILES: the directory where your
- Support
from . import ...
- Recursive discovery of files (currently only works on a flat directory structure)
Roughly equal to the following manual steps:
pyreverse koneko/*.py -o png
- Count the type of each arrow in each module box:
- Dependents = imported by another module (arrow pointing towards box): +1
- Dependencies = imports another module (arrow pointing away from box): -1
- Score = sum
- Proportion = dependents / abs(dependencies + dependents)