Having the following directory tree:
Note: The following behavior is the same with/without the __init__.py
files.
top_package
| top_module.py
|
+---package1
| | module1.py
| | __init__.py
|
\---package2
| module2.py
| __init__.py
with top_module.py
:
from package1.module1 import CLASS1
a = CLASS1()
module1.py
:
from importlib import import_module
class CLASS1:
def __init__(self):
# this works:
foo = getattr(
import_module(name='..module2', package='package2.'), 'CLASS2')()
# this raises ImportError.
foo = getattr(
import_module(name='..module2', package='package2'), 'CLASS2')()
In which the unique difference is that the first uses a dot when defining the package arg. (package='package2.'
), while the other doesn't (package='package2'
).
module2.py
:
class CLASS2:
def __init__(self):
print(f'hi from: {__name__}')
I am having a hard time understanding why in module1.py
the first assignment for foo
works, while the next one doesn't, raising ImportError: attempted relative import beyond top-level package
.
This error occurs when running top_module.py
from its directory:
cd <path-to-top_package>/top_package
python top_module.py
The related info from the docs states
importlib.import_module(name, package=None)
Import a module. The name argument specifies what module to import in absolute or relative terms (e.g. either
pkg.mod
or..mod
). If the name is specified in relative terms, then the package argument must be set to the name of the package which is to act as the anchor for resolving the package name (e.g.import_module('..mod', 'pkg.subpkg')
will importpkg.mod
).
which may already be answering my question but I don't get it correctly.
I was wrongly using import_module
. The main reason is that if name
specifies a relative module, then it is relative w.r.t. the argument package
.
I wrongly thought that name
was relative to the module's __file__
value in which import_module
is called (in this case module1.py
).
Thereby, the first version:
import_module(name='..module2', package='package2.')
Imports package2.module2
since ..module2
specifies that the module is in the parent of the package
arg. The parent of package2.
is package2
.
However,
import_module(name='..module2', package='package2')
tries to import from the parent of package2
, which is unknown, causing ImportError
.