Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Import arbitrary python source file. (Python 3.3+)

How can I import an arbitrary python source file (whose filename could contain any characters, and does not always ends with .py) in Python 3.3+?

I used imp.load_module as follows:

>>> import imp >>> path = '/tmp/a-b.txt' >>> with open(path, 'U') as f: ...     mod = imp.load_module('a_b', f, path, ('.py', 'U', imp.PY_SOURCE)) ... >>> mod <module 'a_b' from '/tmp/a-b.txt'> 

It still works in Python 3.3, but according to imp.load_module documentation, it is deprecated:

Deprecated since version 3.3: Unneeded as loaders should be used to load modules and find_module() is deprecated.

and imp module documentation recommends to use importlib:

Note New programs should use importlib rather than this module.

What is the proper way to load an arbitrary python source file in Python 3.3+ without using the deprecated imp.load_module function?

like image 756
falsetru Avatar asked Sep 25 '13 16:09

falsetru


People also ask

How do I import files into Python 3?

If you have your own python files you want to import, you can use the import statement as follows: >>> import my_file # assuming you have the file, my_file.py in the current directory. # For files in other directories, provide path to that file, absolute or relative.

What is __ import __ in Python?

__import__() . This means all semantics of the function are derived from importlib. __import__() . The most important difference between these two functions is that import_module() returns the specified package or module (e.g. pkg. mod ), while __import__() returns the top-level package or module (e.g. pkg ).

What is import Importlib in Python?

The importlib package provides the implementation of the import statement in Python source code portable to any Python interpreter. This also provides an implementation which is easier to comprehend than one implemented in a programming language other than Python.

How do you import tools in Python?

Importing Modules To make use of the functions in a module, you'll need to import the module with an import statement. An import statement is made up of the import keyword along with the name of the module. In a Python file, this will be declared at the top of the code, under any shebang lines or general comments.


2 Answers

Found a solution from importlib test code.

Using importlib.machinery.SourceFileLoader:

>>> import importlib.machinery >>> loader = importlib.machinery.SourceFileLoader('a_b', '/tmp/a-b.txt') >>> mod = loader.load_module() >>> mod <module 'a_b' from '/tmp/a-b.txt'> 

NOTE: only works in Python 3.3+.

UPDATE Loader.load_module is deprecated since Python 3.4. Use Loader.exec_module instead:

>>> import types >>> import importlib.machinery >>> loader = importlib.machinery.SourceFileLoader('a_b', '/tmp/a-b.txt') >>> mod = types.ModuleType(loader.name) >>> loader.exec_module(mod) >>> mod <module 'a_b'> 

>>> import importlib.machinery >>> import importlib.util >>> loader = importlib.machinery.SourceFileLoader('a_b', '/tmp/a-b.txt') >>> spec = importlib.util.spec_from_loader(loader.name, loader) >>> mod = importlib.util.module_from_spec(spec) >>> loader.exec_module(mod) >>> mod <module 'a_b' from '/tmp/a-b.txt'> 
like image 68
falsetru Avatar answered Oct 13 '22 06:10

falsetru


Updated for Python >= 3.8:

Short version:

>>> # https://docs.python.org/3/library/importlib.html#importing-a-source-file-directly >>> import importlib.util, sys >>> spec = importlib.util.spec_from_file_location(modname, fname) >>> module = importlib.util.module_from_spec(spec) >>> sys.modules[modname] = module >>> spec.loader.exec_module(module) 

Full version:

>>> import importlib.util >>> import sys >>> from pathlib import Path >>> from typing import TYPE_CHECKING >>>  >>>  >>> if TYPE_CHECKING: ...     import types ... ... >>> def import_source_file(fname: str | Path, modname: str) -> "types.ModuleType": ...     """ ...     Import a Python source file and return the loaded module.  ...     Args: ...         fname: The full path to the source file.  It may container characters like `.` ...             or `-`. ...         modname: The name for the loaded module.  It may contain `.` and even characters ...             that would normally not be allowed (e.g., `-`). ...     Return: ...         The imported module  ...     Raises: ...         ImportError: If the file cannot be imported (e.g, if it's not a `.py` file or if ...             it does not exist). ...         Exception: Any exception that is raised while executing the module (e.g., ...             :exc:`SyntaxError).  These are errors made by the author of the module! ...     """ ...     # https://docs.python.org/3/library/importlib.html#importing-a-source-file-directly ...     spec = importlib.util.spec_from_file_location(modname, fname) ...     if spec is None: ...         raise ImportError(f"Could not load spec for module '{modname}' at: {fname}") ...     module = importlib.util.module_from_spec(spec) ...     sys.modules[modname] = module ...     try: ...         spec.loader.exec_module(module) ...     except FileNotFoundError as e: ...         raise ImportError(f"{e.strerror}: {fname}") from e ...     return module ... >>> import_source_file(Path("/tmp/my_mod.py"), "my_mod") <module 'my_mod' from '/tmp/my_mod.py'> 

Original answer for Python 3.5 and 3.6

Shorter version of @falsetru 's solution:

>>> import importlib.util >>> spec = importlib.util.spec_from_file_location('a_b', '/tmp/a-b.py') >>> mod = importlib.util.module_from_spec(spec) >>> spec.loader.exec_module(mod) >>> mod <module 'a_b' from '/tmp/a-b.txt'> 

I tested it with Python 3.5 and 3.6.

According to the comments, it does not work with arbitrary file extensions.

like image 20
Stefan Scherfke Avatar answered Oct 13 '22 06:10

Stefan Scherfke