importhook
is a Python package that lets you configure functions to call whenever a specific module is imported.
pip install importhook
Configure a hook to be called when socket
module is imported.
import importhook
# Setup hook to be called any time the `socket` module is imported and loaded into module cache
@importhook.on_import('socket')
def on_socket_import(socket):
print('"socket" module has been imported')
# Import module
import socket
You can also use importhook
to intercept and modify a module on import by returning a Python module from your hook function.
import importhook
# Setup hook to be called any time the `socket` module is imported and loaded into module cache
@importhook.on_import('socket')
def on_socket_import(socket):
new_socket = importhook.copy_module(socket)
setattr(new_socket, 'gethostname', lambda: 'patched-hostname')
return new_socket
# Import module
import socket
# Prints: 'patched-hostname'
print(socket.gethostname())
importhook
also comes with helpers to reload modules that have already been imported.
import socket
import importhook
# Setup hook to be called any time the `socket` module is imported and loaded into module cache
# DEV: `on_socket_import` will be called immediately because the `socket` module is already loaded
@importhook.on_import('socket')
def on_socket_import(socket):
print('"socket" module has been imported')
# Reload the socket module
# DEV: Reassign to `socket` in case one of our hooks modifies the module
socket = importhook.reload_module(socket)
If a Python developer wants to modify the import behavior they can do so by adding a new importlib.abc.Finder
class into sys.meta_path
.
import sys
# Add our custom `importlib.abc.Finder` to `sys.meta_path`
sys.meta_path.append(MyCustomFinder)
One of the major design decisions we have taken with importhook
is to wrap/overwrite sys.meta_path
.
What it means is that importhook
will continue to work as expected regardless of any other modifications of sys.meta_path
.
There is however one caveat, if you were to do sys.meta_path = [MyCustomFinder] + sys.meta_path
then sys.meta_path
will get
converted back into a list
. Existing modifications to the finders in sys.meta_path
will still work as expected, but any
new finders added will not get hooked.