Search code examples
python-3.xpython-importprojectsetuptoolspython-packaging

Properly structuring Python packages?


I have a Python3.7 package structured like so.

project             # Repository
--\README
--\LICENSE
--\setup.py
--\project          # Source
----\project.py
----\__init__.py    # Init1
----\functions
-------\__init__.py # Init2
-------\moduleA.py
-------\ ...
-------\moduleZ.py

Inside project.py I have the following.

from functions.moduleA import functionA
from functions.moduleB import functionB
...
functionA = functionA
functionB = functionB

Init2 is completely blank. But Init1 has the following.

from .project import functionA
from .project import functionB

But when I execute $ python -c 'import project' inside the Repository directory, I get a ModuleNotFoundError: No module named 'functions'. There is something perhaps very simple that is going wrong here. The import works correctly inside the Source directory though. Ultimately, I'm interested in users installing everything via setup.py and using my project like so.

import project

project.functionA(...)
...
project.functionB(...)

Solution

  • Your project.py file doesn't work as you intend. These lines are causing the error:

    from functions.moduleA import functionA
    from functions.moduleB import functionB
    

    Those imports don't work because functions is not a top-level module, but rather a subpackage that is part of the project package. You can fix them by adding a . at the start of each module name (.functions.moduleA, etc.). I suppose you could also name the absolute module name, if you preferred it for some reason (e.g. project.functions.moduleA).

    The assignment statements also don't do anything. functionA = functionA could be deleted and there would be no difference at all.

    It's not really clear to me what the purpose of the project.py file is. It seems entirely redundant next to the project/__init__.py file, which seems like it's supposed to contain exactly the same values. Probably you should merge them together, into a single file (probably the __init__.py file).

    I'd also think carefully about whether you really need so many subpackages and modules. While it's sometimes just a matter of style, keeping things that are closely related in the same module can be very handy. You certainly do not need a separate module for every function you write!