Generally, to import a python module programatically when you know the file's path, you could do something like this:
import importlib.util
import sys
def import_from_file(module_name, file_path):
spec = importlib.util.spec_from_file_location(module_name, file_path)
module = importlib.util.module_from_spec(spec)
sys.modules[module_name] = module # this step is not necessary, but it's
# probably not a bad idea to have a manually
# imported module stored in sys.modules
spec.loader.exec_module(module)
return module
foo = import_from_file('foo', 'path/to/foo.py')
However, if the file doesn't have a .py extension, Python won't know that your file contains a Python source code, and import will fail. The reason is that the file extensions recognized by the import machinery are more or less hard-coded in the source code of importlib
. As a result, importlib
won't know which loader to use for an unknown file type, and the spec_from_file_location
method will return None
.
A possible solution is to create a SourceFileLoader
object and pass it as the loader
parameter to the spec_from_file_location
method:
from importlib.machinery import SourceFileLoader
...
def import_from_file(module_name, file_path):
loader = SourceFileLoader(module_name, file_path)
spec = importlib.util.spec_from_file_location(module_name, loader=loader)
...
Note however that you no longer need to pass file_path
to spec_from_file_location
, as this information is already stored in the loader object. Thanks to this, the function can be rewritten in a slightly more straightforward manner by replacing spec_from_file_location
with spec_from_loader
:
...
def import_from_file(module_name, file_path):
loader = SourceFileLoader(module_name, file_path)
spec = importlib.util.spec_from_loader(module_name, loader)
...