Search code examples
pythonpython-2.7python-importpython-module

How can I replace a module without importing it?


I would like to test a module named "x" which imports a module named "y". The problem is that it takes several seconds to import y. How can I write a test for x that replaces y with my own module while preventing y from being imported?

All of the Python libraries that I'm aware of that allow one to replace a module require one to first import the module.


Solution

  • So, let's say we have these modules x and y:

    # x.py
    import y
    y.foo()
    
    # y.py
    def foo():
        raise RuntimeError("Nope.")
    

    Given those modules, the following will obviously fail:

    # test_real.py
    import x
    
    $ python test_real.py 
    Traceback (most recent call last):
    File "test_real.py", line 2, in <module>
        import x
    File "x.py", line 3, in <module>
        y.foo()
    File "y.py", line 3, in foo
        raise RuntimeError("Nope.")
    RuntimeError: Nope.
    

    If we have a fake y (called z):

    # z.py
    def foo():
        print "Yessir!"
    

    ... we need to convince Python, before we import x, that y has already been imported (substituting z for it). That's actually quite simple:

    # test_fake.py
    import sys
    sys.modules['y'] = __import__('z')
    
    import x
    

    ... and it works:

    $ python test_fake.py 
    Yessir!