The problem
I've found dozens of articles and tutorials about the basics of using import in Python, but none that would provide a comprehensive guide on setting up your own Python project with multiple packages.
This is my project's structure:
codename/
__init__.py
package1.py
(hasclass1
and is a script)package2.py
(hasclass2
)package3.py
(hasfunction1
and is a script)
test/
__init__.py
test_package1.py
(has unit tests forpackage1
)test_package3.py
(has unit tests forpackage3
)
How do I setup my imports to have the following requirements met (and do all of them make sense?):
class1
,class2
andfunction1
are in namespacecodename
, i.e. this works:import codename obj = codename.class1() codename.function1(obj)
they may be imported the same way using
from codename import *
orfrom codename import class1
function1
can easily accessclass1
(how?)package1
andpackage2
are executable scripts- so are
test_package1.py
andtest_package3.py
- tests are also executable via
python -m unittest discover
- scripts are also executable via
python -m codename.package1
For some reasons I'm having issues with having all of these met and when I try to fix one issue, another one pops out.
What have I tried?
- Leaving
codename/__init__.py
empty satisfies almost all of the requirements, because everything works, but leaves names likeclass1
in their module's namespaces - whereas I want them imported into the package. Adding
from codename.package1 import class1
et al again satisfies most of the requirements, but I get a warning when executing the script viapython -m codename.package1
:RuntimeWarning: 'codename.package2' found in sys.modules \ after import of package 'codename', but prior to execution of \ 'codename.package2'; this may result in unpredictable behaviour
which sort of makes sense...
Running the script via python codename/package1.py
functions, but I guess I would probably like both ways to work.
- I ran into an answer to a similar question that stated that internal modules should not also be scripts, but I don't understand why we get the
-m
switch then? Anyway, extracting themain
s into an externalscripts
directory works, but is it the only canonical way of setting all of this up?