ddpp ddpp
ddpp ddpp

Reputation: 23

Trouble importing a module that imports a module

I'm having trouble with a python package that uses separate modules to structure code. The package itself is working, however when imported from another environment fails with a ModuleNotFound error. Here's the structure:

Project-root
|
|--src/
|    __init__.py
|    module_a.py
|    module_b.py
|    module_c.py
|    module_d.py
|--tests
etc.

In module_a.py I have:

from module_a import function_a1,...
from module_b import function_b1,...
from module_c import function_c1,...

In module_c I import module_d like:

from module_d import function_d1,...

As mentioned above, executing module_a or module_c directly from the CLI work as expected, the unit tests I've created in the test directory also work (with the help of sys.path.insert), however if I create a new environment and import the package I get the following error:

>>> import module_a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/<abs_path>/.venv/lib/python3.9/site-packages/module_a.py", line 22, in <module>
    from module_c import function_c1, function_c2
  File /<abs_path>/.venv/lib/python3.9/site-packages/module_c.py", line 9, in <module>
    import module_d
ModuleNotFoundError: No module named 'module_d'
>>> 

I've exhausted all ideas how to overcome this, besides combining the code of modules c and d in one file, which I'd hate to do, or rethink the flow so that all modules are imported from module_a. Any suggestions how to approach this would be greatly appreciated. Update: It turned out to be a typing mistake in the name of module_d in setup.py. For whatever reason python setup.py install was failing silently or I wasn't reading the logs carefully.

Upvotes: 2

Views: 2950

Answers (1)

Lenormju
Lenormju

Reputation: 4368

The problem comes down to understanding the basics of the import system and the PYTHONPATH.

When you try to import a module (import module_a), Python will search in order in every directory listed in sys.path. If in one of them it finds a directory that matches the name (module_a)1, then it runs the __init__.py file is such exist. If it finds a file, it gets directly converted to a module.

When you get an ImportError, it means that there is no directory in sys.path containing a file/directory with the name asked.

You said for your tests you did something like sys.path.insert(0, "some/path/"), but it is not a solution, just a broken fix.

What you should do is set your PYTHONPATH environment variable to contain the directory where your modules are located, Project-root/src in your case. That way, no need to ever use sys.path.insert, or fiddle with relative/absolute paths in import statements.

When you create your new environment, just set your environment variable PYTHONPATH to include Project-root/src and you are done. This is how installing regular Python modules (libraries) work : they are all put into a directory in site-packages.


1: this changed since old Python versions, it used to be required for the directory to contain an __init__.py file, see PEP-420

Upvotes: 2

Related Questions