开发者

Load python module not from a file

I've got some python code in a library that attempts to load a simple value from a module that will exist for the applications that use this library

from somemodule import simplevalue

Normally, the application that uses the library will have the module file and everything wo开发者_如何转开发rks fine. However, in the unit tests for this library the module does not exist. I know that I can create a temporary file and add that file to my path at runtime, but I was curious if there is a way in python to load something in to memory that would allow the above import to work.

This is more of a curiosity, saying "add the module to your test path" is not helpful :P


It is. Use types.ModuleType to create a new module object, then add it to sys.modules:

sys.modules["somename"] = types.ModuleType("somename")

You can then do import somename. If you need to add classes or functions to it, import it before calling your test script, and just add functions to it:

def myfunc(x, y, z):
    ...

somename.myfunc = myfunc

It should go without saying, but just in case: this is largely an academic curiosity. It has some uses for testing, but other than that, stick to importing things the usual way.

Incidentally, how I know about this: I've come across the technique used in testing, to make a "stub" for the _winreg module on non-Windows systems. Here it is in use.


It isn't necessary to create a module. No Python code cares whether somemodule.simplevalue is actually a reference to an attribute of a module. To do so, a program would need to check the type of somemodule. Why bother?

Since you just want the single value from the module and are importing it into your own namespace, just define it:

simplevalue = 42

If you like, use try/except to try to import the real module first.

try:
    from somemodule import simplevalue
except ImportError:
    simplevalue = 42

If you are importing the entire module but only using one value, you can use a class to define a namespace.

try:
    import somemodule
except ImportError:
    class somemodule(object):
        simplevalue = 42

Now somemodule.simplevalue refers to the value regardless of whether the module is available.

If you want other modules that also import somemodule to see your faked-up class-as-module, as you would in your unit test, just do this afterward:

import sys
sys.modules["somemodule"] = somemodule


Your system under test (sut in my example) needs to be able to cope with the fact that somemodule may not exist, so you can trap the ImportError:

#!/usr/bin/env python

try:
    from somemodule import simplevalue
except ImportError, e:
    if 'somemodule' in e:
        '''We expect that to happen in the unittest but you should log something for when
         this happens in production'''

def fn():
    return simplevalue

Then you can inject a value in your unittest:

#!/usr/bin/env python

import unittest
import sut

class T(unittest.TestCase):

    def test_fn(self):
        sut.simplevalue = 42
        self.assertEquals(42, sut.fn())


if __name__ == '__main__':
    unittest.main()
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜