I am trying to create a package with multiple .py
files. When I try to import a file from the package from a script in the parent directory, a second import between files within the package fails with ModuleNotFoundError
. What is going on here, what am I doing wrong, and how do I fix this?
My file layout:
python_path_test/
parent.py
mypackage/
__init__.py
child.py
sibling.py
parent.py
:
import mypackage.child
mypackage.child.foo()
subdir/__init__.py
is empty
mypackage/child.py
:
import sibling
def foo():
print("foo")
sibling.bar()
mypackage/sibling.py
:
def bar():
print("bar")
Now, when I try to run parent.py
, I get a ModuleNotFoundError
:
C:\>cd \python_path_test
C:\python_path_test>py -3 parent.py
Traceback (most recent call last):
File "C:\python_path_test\parent.py", line 1, in <module>
import mypackage.main
File "C:\python_path_test\mypackage\main.py", line 1, in <module>
import sibling
ModuleNotFoundError: No module named 'sibling'
I expected import sibling
in child.py
to succeed because sibling.py
is in the same directory as child.py
.
In C and C++ the directory containing the current source file is always the first entry in the search path, but clearly that is not what is going on here, since import sibling
in child.py
is failing even though both files are in the same directory. I must be doing something silly, because cross-importing files that are in the same directory is the most basic thing you'd want to do when splitting code into multiple files. What is the correct way to proceed?
EDIT (revised)
Mike suggested adding a dot, to use relative imports (which I am not familiar with). But when I changed child.py
to use import .sibling
I got a syntax error. Karl and Varshitha both pointed out that I should write from . import sibling
-- that works for the example given above, but then it breaks running scripts from the command line in the package directory. For example
mypackage/script.py
from . import child
child.foo()
when run, outputs:
C:\python_path_test>cd mypackage
C:\python_path_test>py -3 script.py
Traceback (most recent call last):
File "C:\python_path_test\mypackage\script.py", line 1, in <module>
from . import child
ImportError: attempted relative import with no known parent package
This same breakage occurs if I want to run files in mypackage
that contain if __name__ == '__main__':
sections (when they use relative imports). I have seen explanations of why this error occurs (files run as scripts do not set a parent package name) but I do not know the correct way to resolve this. It seems that if I use relative imports, I lose the ability to run scripts inside my package directory. I have discovered that I can use the -m
flag, and run the script from the parent directory using:
cd python_path_test
py -3 -m mypackage.script
but that is rather unintuitive and inconvenient, which makes me think that I am still doing something wrong.
Furthermore, if I have a Jupyter notebook in mypackage/
containing the single cell import child
or from . import child
it fails with the same error and I know of no workaround.