Search code examples
pythonpython-3.xmonkeypatching

Monkey patch the module that imports this one


So, I have a Python application that has this functionality where any module-like file in the extensions subdirectory of the program directory gets imported at some early point in the application's initialization process.

This looks something like this (assume this is my_application.py):

def do_init():
    for thefname in glob.iglob(os.path.join(".","extensions","*")):
        SourceFileLoader(os.path.basename(thefname),thefname).load_module()
    #do other init stuff...

if __name__ == "__main__":
    do_init()
    do_cool_things()

Now, I'd like to be able to have a .py file in that extensions directory that goes something like this:

import my_application
def my_cool_things():
    print("The original things have been overridden.")
my_application.do_cool_things = my_cool_things

And this works... for future imports of my_application. But the do_cool_things call inside the if __name__ == "__main__" guard exhibits the original behavior. Why is this happening and how can I make that call exhibit the modified behavior?


Solution

  • The module created by running a script called my_application.py surprisingly isn't my_application. The module created by running a script is __main__. Of course, the module created by importing a file called my_application.py would be called my_application.

    Two solutions to your problem are to replace import my_application with either import __main__ or import builtins.

    Simple demonstration:

    #x.py
    import y
    print ("Hello", hello)
    

    and

    #y.py
    import __main__
    __main__.hello = 'world'
    

    Test on Ubuntu 14.04 with Python 3.4.3:

    $ python3 x.py
    Hello world
    $