8

I am trying to figure out how to programmatically execute a module that contains relative imports.

psuedo code

spec = importlib.util.spec_from_file_location(name, path)
mod = importlib.util.module_from_spec(spec)
spec.loader.exec_module(mod)

Where name is the class, and path is the absolute path to the .py

When the module that is being loaded contains relative imports, the call to the exec_module throws the following exception:

attempted relative import with no known parent package

Is there a way to programmatically execute a python module that itself contains relative imports? If so, how?

2 Answers 2

6

Your code works fine for me, as is.

One possible issue is what the value of the name you're using is. In order for relative imports to work, you need to fully specify the module name (e.g. name = "package1.package2.mymodule").

For example:

runimport.py

import importlib
import os

name = "testpack.inside" # NOT "inside"

spec = importlib.util.spec_from_file_location(name, 
    os.path.join(os.path.dirname(__file__), 'testpack/inside.py'))
mod = importlib.util.module_from_spec(spec)
spec.loader.exec_module(mod)

testpack/init.py

# empty

testpack/inside.py

from . import otherinside
print('I got', otherinside.data)

testpack/otherinside.py

data = 'other inside'

Now, python3 runimport.py prints "I got other inside". If you replace the name with "inside", it throws the error you describe.

Sign up to request clarification or add additional context in comments.

Comments

1

The problem is that the original PEP 451 created 10 years ago is buggy and claims that your import specification contains all data needed to import a module. In reality the module spec does not properly track package structures in python. Consequently you need to specify exactly where in the package structure your module is loaded from. That means you need to add mypackage.subpack2.subpackge2.hairy3.mypackage in calls to some of the loading calls. For instance

find_spec("mypackage")

is incorrect and you need to use

find_spec("mypackage.subpack2.subpackge2.hairy3.mypackage")

to correctly load the module. In your case you need to find the package root and add that to name in call spec_from_file_location. Tragically the copypasta solution is too long and hairy to fit in this comment. Try complaining on python forums about this isssue to get it fixed.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.