A deep dive
In Python, an import hook has two main components:
A Finder which looks for the code (usually a .py file) that is requested by an
A Loader which retrieves the source code, executes it, an returns a module object.
The order of execution is the following
The diagram above illustrates only the main steps. These can be broken down further as follows.
Normally, for creating import hooks and as shown above,
it is important to distinguish
the two main phases, that is creating a
Finder and a
Using ideas, these are automatically done for us, and we can focus
on various parts over which we can have control.
In the diagram below:
Inside each of the major blocks (Decode, AST, Bytecode), we don’t have control over the individual components; however, we could, in principle, substitute our own version of the entire block.
There exists at least one example for anything (excluding major blocks) with a white background.
Anything with a light blue background indicates that some examples of this should be doable. Ideally, at least one example of each possible case should be added.
Options to create a custom hook
- ideas.import_hook.create_hook(callback_params=None, create_module=None, console_dict=None, exec_=None, extensions=None, first=True, hook_name=None, ipython_ast_node_transformer=None, module_class=None, source_init=None, transform_ast=None, transform_bytecode=None, transform_source=None)
Function to facilitate the creation of an import hook.
Each of the following parameter is optional; most of these are never needed except in some unusual import hooks.
Usually, at least one of
transform_sourceshould be specified.
callback_params: a dict containing keyword parameters to be passed back to the
create_module: a custom function to create a module object instead of using Python’s default.
console_dict: a dict object used as ‘locals’ with the Ideas console, instead of its usual default.
exec_: a custom method used to execute the source code inside a module’s dict.
extensions: a list of file extensions, other than the usual .py, etc., used to identify modules containing source code.
True, the custom hook will be used as the first location in
sys.meta_path, to look for source files.
hook_name: used to give a more readable
reprto the hook created.
ipython_ast_node_transformer: used to do AST transformations in an IPython/Jupyter environment. It should be a class derived from
ast.NodeTransformerand return a
module_class: custom class to use for the module created instead of the default one assigned by Python.
source_init: custom code to be executed before any code from a user is executed. For example, if one creates an import hook that treats every
Decimalobject, this custom code could be:
from decimal import Decimal
transform_ast: used to do AST transformations in a Python environment (excluding IPython/Jupyter). It should be a class derived from
ast.NodeTransformer, eventually returning a tree object.
transform_bytecode: used to mutate a code object.
transform_source: used to transform some source code prior to execution.
In the last diagram shown above, there is a block labeled ‘Decode’. Changing the way that Python processes code during this phase does not require the creation of an import hook; instead, it requires the use of a custom codec.
An example is shown in a later section.