I want to import a function from another file in the same directory.
Sometimes it works for me with from .mymodule import myfunction
but sometimes I get a:
SystemError: Parent module '' not loaded, cannot perform relative import
Sometimes it works with from mymodule import myfunction
, but sometimes I also get a:
SystemError: Parent module '' not loaded, cannot perform relative import
I don't understand the logic here, and I couldn't find any explanation. This looks completely random.
Could someone explain to me what's the logic behind all this?
I ran into this issue. A hack workaround is importing via an if/else block like follows:
Hopefully, this will be of value to someone out there - I went through half a dozen stackoverflow posts trying to figure out relative imports similar to whats posted above here. I set up everything as suggested but I was still hitting
ModuleNotFoundError: No module named 'my_module_name'
Since I was just developing locally and playing around, I hadn't created/run a
setup.py
file. I also hadn't apparently set myPYTHONPATH
.I realized that when I ran my code as I had been when the tests were in the same directory as the module, I couldn't find my module:
However, when I explicitly specified the path things started to work:
So, in the event that anyone has tried a few suggestions, believes their code is structured correctly and still finds themselves in a similar situation as myself try either of the following if you don't export the current directory to your PYTHONPATH:
$ PYTHONPATH=. python3 test/my_module/module_test.py
PYTHONPATH=.
, create asetup.py
file with contents like the following and runpython setup.py development
to add packages to the path:It's quite common to have a layout like this...
...with a
mymodule.py
like this......a
myothermodule.py
like this......and a
main.py
like this......which works fine when you run
main.py
ormypackage/mymodule.py
, but fails withmypackage/myothermodule.py
, due to the relative import...The way you're supposed to run it is...
...but it's somewhat verbose, and doesn't mix well with a shebang line like
#!/usr/bin/env python3
.The simplest fix for this case, assuming the name
mymodule
is globally unique, would be to avoid using relative imports, and just use......although, if it's not unique, or your package structure is more complex, you'll need to include the directory containing your package directory in
PYTHONPATH
, and do it like this......or if you want it to work "out of the box", you can frob the
PYTHONPATH
in code first with this...It's kind of a pain, but there's a clue as to why in an email written by a certain Guido van Rossum...
Whether running scripts inside a package is an antipattern or not is subjective, but personally I find it really useful in a package I have which contains some custom wxPython widgets, so I can run the script for any of the source files to display a
wx.Frame
containing only that widget for testing purposes.if both packages are in your import path (sys.path), and the module/class you want is in example/example.py, then to access the class without relative import try:
Explanation
From PEP 328
At some point PEP 338 conflicted with PEP 328:
and to address the issue, PEP 366 introduced the top level variable
__package__
:(emphasis mine)
If the
__name__
is'__main__'
,__name__.rpartition('.')[0]
returns empty string. This is why there's empty string literal in the error description:The relevant part of the CPython's
PyImport_ImportModuleLevelObject
function:CPython raises this exception if it was unable to find
package
(the name of the package) ininterp->modules
(accessible assys.modules
). Sincesys.modules
is "a dictionary that maps module names to modules which have already been loaded", it's now clear that the parent module must be explicitly absolute-imported before performing relative import.Note: The patch from the issue 18018 has added another
if
block, which will be executed before the code above:If
package
(same as above) is empty string, the error message will beHowever, you will only see this in Python 3.6 or newer.
Solution #1: Run your script using -m
Consider a directory (which is a Python package):
All of the files in package begin with the same 2 lines of code:
I'm including these two lines only to make the order of operations obvious. We can ignore them completely, since they don't affect the execution.
__init__.py and module.py contain only those two lines (i.e., they are effectively empty).
standalone.py additionally attempts to import module.py via relative import:
We're well aware that
/path/to/python/interpreter package/standalone.py
will fail. However, we can run the module with the-m
command line option that will "searchsys.path
for the named module and execute its contents as the__main__
module":-m
does all the importing stuff for you and automatically sets__package__
, but you can do that yourself in theSolution #2: Set __package__ manually
Please treat it as a proof of concept rather than an actual solution. It isn't well-suited for use in real-world code.
PEP 366 has a workaround to this problem, however, it's incomplete, because setting
__package__
alone is not enough. You're going to need to import at least N preceding packages in the module hierarchy, where N is the number of parent directories (relative to the directory of the script) that will be searched for the module being imported.Thus,
Add the parent directory of the Nth predecessor of the current module to
sys.path
Remove the current file's directory from
sys.path
Import the parent module of the current module using its fully-qualified name
Set
__package__
to the fully-qualified name from 2Perform the relative import
I'll borrow files from the Solution #1 and add some more subpackages:
This time standalone.py will import module.py from the package package using the following relative import
We'll need to precede that line with the boilerplate code, to make it work.
It allows us to execute standalone.py by filename:
A more general solution wrapped in a function can be found here. Example usage:
Solution #3: Use absolute imports and setuptools
The steps are -
Replace explicit relative imports with equivalent absolute imports
Install
package
to make it importableFor instance, the directory structure may be as follows
where setup.py is
The rest of the files were borrowed from the Solution #1.
Installation will allow you to import the package regardless of your working directory (assuming there'll be no naming issues).
We can modify standalone.py to use this advantage (step 1):
Change your working directory to
project
and run/path/to/python/interpreter setup.py install --user
(--user
installs the package in your site-packages directory) (step 2):Let's verify that it's now possible to run standalone.py as a script:
Note: If you decide to go down this route, you'd be better off using virtual environments to install packages in isolation.
Solution #4: Use absolute imports and some boilerplate code
Frankly, the installation is not necessary - you could add some boilerplate code to your script to make absolute imports work.
I'm going to borrow files from Solution #1 and change standalone.py:
Add the parent directory of package to
sys.path
before attempting to import anything from package using absolute imports:Replace the relative import by the absolute import:
standalone.py runs without problems:
I feel that I should warn you: try not to do this, especially if your project has a complex structure.
As a side note, PEP 8 recommends the use of absolute imports, but states that in some scenarios explicit relative imports are acceptable:
To obviate this problem, I devised a solution with the repackage package, which has worked for me for some time. It adds the upper directory to the lib path:
Repackage can make relative imports that work in a wide range of cases, using an intelligent strategy (inspecting the call stack).