Python 3 import hooks
<p>I'm trying to implement an "import hook" in Python 3. The hook is supposed to add an attribute to every class that is imported. (Not really <em>every</em> class, but for the sake of simplifying the question, let's assume so.)</p>

<p>I have a loader defined as follows:</p>

<pre><code>import sys

class ConfigurableImports(object):

    def find_module(self, fullname, path):
        return self

    def create_module(self, spec):
        # ???

    def exec_module(self, module):
        # ???

sys.meta_path = [ConfigurableImports()]
</code></pre>

<p>The documentation states that as of 3.6, loaders will have to implement both <code>create_module</code> and <code>exec_module</code>. However, the documentation also has little indication what one should do to implement these, and no examples. My use case is very simple because I'm only loading Python modules and the behavior of the loader is supposed to be almost exactly the same as the default behavior.</p>

<p>If I could, I'd just use <code>importlib.import_module</code> and then modify the module contents accordingly; however, since importlib leverages the import hook, I get an infinite recursion.</p>

<p>EDIT: I've also tried using the <code>imp</code> module's <code>load_module</code>, but this is deprecated.</p>

<p>Is there any easy way to implement this functionality with import hooks, or am I going about this the wrong way?</p>

<p>Imho, if you only need to alter the module, that is, play with it after it has been found and loaded, there's no need to actually create a full hook that finds, loads and returns the module; just patch <code>__import__</code>.</p>

<p>This can easily be done in a few lines:</p>

<pre><code>import builtins 
from inspect import getmembers, isclass

old_imp = builtins.__import__

def add_attr(mod):
    for name, val in getmembers(mod):
        if isclass(val):
            setattr(val, 'a', 10)

def custom_import(*args, **kwargs):
    m = old_imp(*args, **kwargs)
    add_attr(m)
    return m

builtins.__import__ = custom_import
</code></pre>

<p>Here, <code>__import__</code> is replaced by your custom import that calls the original <code>__import__</code> to get the loaded module and then calls a function <code>add_attr</code> that does the actual modification of the classes in a module (with <code>getmembers</code> and <code>isclass</code> from <code>inspect</code>) before returning the module.</p>

<p>Of course this is created in a way that when you <code>import</code> the script, the changes are made. </p>

<p>You can and probably should create auxiliary functions that <code>restore</code> and change it again if needed i.e things like:</p>

<pre><code>def revert(): builtins.__import__ = old_imp

def apply(): builtins.__import__ = custom_import
</code></pre>

<p>A context-manager might also be a cool addition too.</p>

<p>So you can call it when you need to get your </p>

python python-3.x