phy-imports-resolver 0.1.4
Resolve imports of a python file or module, with site packages & builtin modules excluded.
License: MIT
Requires Python: <4,>=3.10

# PHY-imports-resolver

<p align="left">
  <a href="#"><img alt="PyPI" src="https://img.shields.io/pypi/v/phy-imports-resolver.svg"></a>
  <a href="#"><img alt="Python Versions" src="https://img.shields.io/pypi/pyversions/phy-imports-resolver.svg"></a>
  <a href="#"><img alt="License" src="https://img.shields.io/badge/license-MIT-blue.svg"></a>
</p>

Resolve imports of a python file or module recursively, exclude site packages & builtin modules.

This project is part of [`phy`](https://github.com/phy-precompiler).

## Install

If you intend to use this package as a library within your Python project, install it as follows:

```shell
pip install phy-imports-resolver
```

If you plan to use its command-line interface (CLI) to generate graphic diagram, install the `cli` 
optional dependencies:

```shell
pip install phy-imports-resolver[cli]
```

## How to use

Suppose the layout of your python project is:

```shell
src/
├──my_project/
│  ├──file1.py
│  ├──file2.py
│  ├──pkg1.py
│  │  ├── file3.py
│  │  └── __init__.py
│  └──__init__.py
└──script1.py
```

To resolve the imports tree: 

+ Firstly you MUST specify a root directory named `project_dir` to search within; in this case, 
it is `src`. If `project_dir` is not explicitly provided, current directory is used.

+ An entry file path is also required as the start point for the resolver to search from. If you want to resolve from a package instead of a file, use the `__init__.py` file of the package as the entry file.

In this case, if `script1.py` is the entry file to resolve, call the `resolve(entry_file)` method:

```python
import phy_imports_resolver
from pathlib import Path

project_dir = Path('./src')
entry_file = project_dir / 'script1.py'

mod_imports_node = phy_imports_resolver.resolve(entry_file, project_dir)
```

The result `mod_imports_node` is a `ModuleImportsNode` object, which represents a file module or sub package in a hierarchical tree structure of importing relationship. See the definition of `ModuleImportsNode`:

```python
class ModuleImportsNode:
    def __init__(self, mod, project_dir, imports: List['ModuleImportsNode'], **kwargs):
      ...
```

where attribute `mod` stands for the file or package itself, and list attribute `imports` holds other modules imported to itself.

Recursively iterate the `imports` attributes of the entry `ModuleImportsNode` object will given the entire importing relationship tree. 

The complete API docs can be found [here](./docs/module.md).

### use the CLI

```shell
Usage: phy-resolve-imports [OPTIONS] FILE

  Resolve the imports of a python file or module, recursively.

  FILE: path to the entry code file; to resolve package, use path 
        of the `__init__.py` file of the package.

Options:
  -f, --format [xml|png|svg]  Specify the output format  [default: xml]
  -o, --output PATH           Optional output file path.
  --help                      Show this message and exit.
```

For the CLI, current work directory will be used as the root directory to search within.

# API docs

+ [module](docs/module.md)
+ [resolver](docs/resolver.md)
+ [types](docs/types.md)

These markdown docs are generated by [`pydoc-markdown`](https://pypi.org/project/pydoc-markdown/):

```shell
pydoc-markdown -I src -m phy_imports_resolver --render-toc > docs/module.md

pydoc-markdown -I src -m phy_imports_resolver.resolver --render-toc > docs/resolver.md

pydoc-markdown -I src -m phy_imports_resolver.types --render-toc > docs/types.md
```

## Reminder

This package DOES NOT support `importlib` to dynamically import modules, for the module imported by `importlib` can be
variable and thus can only be determined at runtime; otherwise, if the the module imported by `importlib` is
constant string, the developer can absolutely use import statement (non-top-placed) instead.