我可以在Python中“伪造”一个包(或至少一个模块)以进行测试吗?
我想在Python里假装有一个包。我想定义一些东西,这样代码就可以这样写:
from somefakepackage.morefakestuff import somethingfake
而且somefakepackage在代码里被定义了,下面的内容也是如此。这可能吗?这样做的原因是为了让我的单元测试误以为我有一个包(或者像我在标题里说的,一个模块)在Python的路径里,实际上这只是为了这个单元测试假装出来的东西。
5 个回答
8
我从其他回答中获取了一些想法,做成了一个Python装饰器 @modulize
,这个装饰器可以把一个函数变成一个模块。然后你就可以像平常一样导入这个模块。下面是一个例子。
@modulize('my_module')
def my_dummy_function(__name__): # the function takes one parameter __name__
# put module code here
def my_function(s):
print(s, 'bar')
# the function must return locals()
return locals()
# import the module as usual
from my_module import my_function
my_function('foo') # foo bar
这个装饰器的代码如下:
import sys
from types import ModuleType
class MockModule(ModuleType):
def __init__(self, module_name, module_doc=None):
ModuleType.__init__(self, module_name, module_doc)
if '.' in module_name:
package, module = module_name.rsplit('.', 1)
get_mock_module(package).__path__ = []
setattr(get_mock_module(package), module, self)
def _initialize_(self, module_code):
self.__dict__.update(module_code(self.__name__))
self.__doc__ = module_code.__doc__
def get_mock_module(module_name):
if module_name not in sys.modules:
sys.modules[module_name] = MockModule(module_name)
return sys.modules[module_name]
def modulize(module_name, dependencies=[]):
for d in dependencies: get_mock_module(d)
return get_mock_module(module_name)._initialize_
这个项目可以在 GitHub上找到。特别是,我是为了编程比赛而创建这个的,因为比赛只允许参赛者提交一个 .py
文件。这样,你就可以先开发多个 .py
文件,最后再把它们合并成一个 .py
文件。
22
是的,你可以创建一个假的模块:
from types import ModuleType
m = ModuleType("fake_module")
import sys
sys.modules[m.__name__] = m
# some scripts may expect a file
# even though this file doesn't exist,
# it may be used by Python for in error messages or introspection.
m.__file__ = m.__name__ + ".py"
# Add a function
def my_function():
return 10
m.my_function = my_function
注意,在这个例子中,它使用了一个真实的模块(ModuleType
),因为有些Python代码可能会期待模块,而不是一个虚假的类。
这可以变成一个工具函数:
def new_module(name, doc=None):
import sys
from types import ModuleType
m = ModuleType(name, doc)
m.__file__ = name + '.py'
sys.modules[name] = m
return m
print(new_module("fake_module", doc="doc string"))
现在其他脚本可以运行:
import fake_module
47
当然可以。你可以先定义一个类,把你需要的东西放进去,然后把这个类赋值给 sys.modules["classname"]
。
class fakemodule(object):
@staticmethod
def method(a, b):
return a+b
import sys
sys.modules["package.module"] = fakemodule
你也可以使用一个单独的模块(可以叫它 fakemodule.py
):
import fakemodule, sys
sys.modules["package.module"] = fakemodule