pythonpython-importsetuptoolspython-packagingpython-importlib

Dynamically importing libraries with importlib on setuptools entrypoint


What I am trying to achieve

My goal is, after installing the python package, to be able to run a command from a script that was not installed together.

Example

$ excommand
Hello!

Directory Structure

.
├── A
    ├── __init__.py
    └── cli.py
├── .venv
├── pyproject.toml
├── setup.cfg
├── extra.py
└── extra_test.py

cli.py

import importlib

def main():
    getattr(importlib.import_module('extra'), 'hello')()

extra.py

def hello():
    print("Hello!")

extra_test.py

import importlib

getattr(importlib.import_module('extra'), 'hello')()

pyproject.toml

[build-system]
requires = [ "setuptools" ]
build-backend = "setuptools.build_meta"

setup.cfg

[metadata]
name = A
version = 1.0.0

[options]
packages = find:

[options.entry_points]
console_scripts = 
    hello = A.cli:main

The Problem

After installing the package:

$ pip install .

The command hello does not work because importlib raises an Error:

$ hello
ModuleNotFoundError: No module named 'extra'

What was tried

I have assured that has something to do with the installation or importlib, because if I run python3 extra_test.py it runs normally and it does exactly the same as the command hello is suposed to do.


Solution

  • I encountered the same problem.

    Refer to @sinoroc's debugging suggestions. It is found that if you start the script from entry_points, sys.path does not have os.getcwd().

    finally:

    # cli.py
    sys.path.append("./")