I'm banging my head against the wall with some basic Python importing. I have simplified the problem as much as possible hoping I'd be able to expand this to a larger scale if I understand how this works
Here is the dilemma -
run.py
from inside the submodule p1
works, but NOT when it's at the top level. Why?
(version Python 3.6.3)
Structure:
/sandbox
__init__.py
/p1
__init__.py
file1.py
run.py
run.py
/sandbox/p1/__init__.py
__all__ = ["file1", "file2"]
/sandbox/p1/file1.py
from file2 import B
class A(object):
pass
/sandbox/p1/file2.py
class B(object):
pass
/sandbox/p1/run.py
from file1 import A
a = A()
/sandbox/run.py
from p1 import file1
a = file1.A()
Doing:
python p1/run.py
(works fine)
python run.py
Traceback (most recent call last):
File "run.py", line 2, in
from p1 import file1
File ".../sandbox/p1/file1.py", line 1, in
from file2 import B
ModuleNotFoundError: No module named 'file2'
(I) no module named 'file2'
You encountered No module named 'file2'
because you run run.py
outside a package, when file1
import file2
, python cannot find file2
as the module directory not in module search path.
For your scenario, file1
& file2
are 2 modules which in the same package, for this situation, suggest you use relative import
, this is the best practice.
file1.py
from .file2 import B
class A(object):
pass
Then, python run.py
works.
(II) attempted relative import with no known parent package
As you mentioned you will see next if execute python p1/run.py
:
attempted relative import with no known parent package
What does it mean?
This because relative import
can just be supported in the module which in package.
You may say file1.py
is in package p1
, why still see the error?
This is because python use __name__
to determine if this module in package or not, not by the position of it.
Change file1.py
as follows:
print(__name__)
from .file2 import B
class A(object):
pass
Next is the output:
python run.py
p1.file1
python p1/run.py
file1
For python p1/run.py
, because it runs in the package, python will fail to know it is in a package, so output is file1
.
If __name__
does not has .
, python will think it's not in package, so relative import failure.
(III) Finally, what if you really want to execute python p1/run.py
, e.g. unittest your package?
Use python -m p1.run
, this should works to execute top script which inside a package.
Python makes it intentionally difficult to mix scripts in a modules. The way this can be handled is like this:
/project
/scripts
run.py
/sandbox
__init__.py
/p1
__init__.py
file1.py
file2.py
/project/sandbox/p1/file1.py
from .file2 import B
class A(object):
pass
/project/sandbox/p1/file2.py
class B(object):
pass
/project/scripts/run.py
from sandbox.p1.file1 import A
a = A()
I make sure that the path to /project
is in a .pth
file in the site-packages of the virtual environment I want to use it from.
conda
If you use conda, you can use conda develop