Dynamic imports + relative imports in Python 3

Z

zildjohn01

This is a copy-paste of a StackOverflow question. Nobody answered
there, but I figured I might have better luck here.

I have a Python 3 project where I'm dynamically importing modules from
disk, using `imp.load_module`. But, I've run into an problem where
relative imports fail, when the relative import occurs within a
dynamically imported module.

From what I've read, I came to the conclusion that only `__file__`,
`__path__`, `__package__`, and `__name__` were used by the default
importer when determining the path of an import. Yet, I've verified
these in the code below, and it still fails when dynamically imported.
(It works when imported in the interpreter with an updated `sys.path`)

# File structure:
# [root]
# ├─ __init__.py
# ├─ board.py
# └─ test.py

# Contents of 'board.py':
import os, sys
import root # Already imported... just need a reference

ROOT_DIR = os.path.dirname(root.__file__)
assert root is sys.modules['root']
assert root.__package__ is None
assert root.__name__ == 'root'
assert root.__file__ == os.path.join(ROOT_DIR, '__init__.py')
assert not hasattr(root, '__path__')

xx = object()
assert xx is sys.modules['root.board'].xx
assert __package__ is None
assert __name__ == 'root.board'
assert __file__ == os.path.join(ROOT_DIR, 'board.py')
assert not hasattr(sys.modules['root.board'], '__path__')

assert os.path.isfile(os.path.join(ROOT_DIR, 'test.py'))
from . import test # ImportError('cannot import name test',)

But if I hack `sys.path` and reimport the current package just before
the failed import, it works fine:

oldroot = root
del sys.modules['root']
try:
sys.path.append(os.path.dirname(ROOT_DIR))
import root
finally:
sys.path.pop(-1)
from . import test # No error here

And further, the four golden attributes mentioned above are the same
in both the new and old packages:

assert oldroot.__package__ == root.__package__
assert oldroot.__name__ == root.__name__
assert oldroot.__file__ == root.__file__
assert not hasattr(root, '__path__')

Which means that `__package__`, `__name__`, `__file__`, and `__path__`
can't be the full story. Are there any other attributes that Python
uses to locate imports? What am I overlooking that would cause the
import to fail?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,535
Members
45,007
Latest member
obedient dusk

Latest Threads

Top