Python——重新加载模块级对象 我想做什么

Python——重新加载模块级对象 我想做什么,python,django,unit-testing,testing,Python,Django,Unit Testing,Testing,我正在尝试编写单元测试,以检查我的regexp是否正确构造: mediamanager/models.py 进口稀土 从django.conf导入设置 文件类型\u re={} 对于键,settings.MM_FILETYPES.items中的exts: filetypes_re[key]=re.compiler'{}.format'|'.joinexts 注意:事实上,我根本不知道我为什么要写这个单元测试,因为这段代码比straighforward还要复杂……但这不是重点 如您所见,最终的re

我正在尝试编写单元测试,以检查我的regexp是否正确构造:

mediamanager/models.py 进口稀土 从django.conf导入设置 文件类型\u re={} 对于键,settings.MM_FILETYPES.items中的exts: filetypes_re[key]=re.compiler'{}.format'|'.joinexts 注意:事实上,我根本不知道我为什么要写这个单元测试,因为这段代码比straighforward还要复杂……但这不是重点

如您所见,最终的regexp取决于用户可以设置的变量settings.MM_文件类型。我需要测试特定的输入,对于这种情况,Django提供decorator@override\u设置,临时覆盖设置值:

mediamanager/tests.py 导入单元测试 从django.test.utils导入覆盖设置 从mediamanager.models导入文件类型,…导入我们要测试的所有内容 类ModelsTestCaseunittest.TestCase: @覆盖设置SMM_文件类型={'image':['jpg','png','gif'], '文档':['pdf','txt'], '音频':['mp3',wav']} def test_filetype_reself: 文件类型_re_exp={'image':'jpg | png | gif', “文档”:“pdf | txt”, “音频”:“mp3 | wav”} 对于键,filetypes\u re\u exp.items中的值: self.assertEqualvalue,文件类型\u re[key]。模式 不幸的是,这次考试没有通过。模块mediamanager.models在覆盖设置之前加载,因此使用旧设置编译文件类型。我需要以某种方式重新加载它以使新设置生效

问题 我以这种方式更改了unittest:

@覆盖设置SMM_文件类型={'image':['jpg','png','gif'], '文档':['pdf','txt'], '音频':['mp3',wav']} def test_filetype_reself: 从sys.modules获取模块对象的import mediamanager.models具有相同的结果 重新加载MediaManager.models filetypes\u re=mediamanager.models.filetypes\u re 文件类型_re_exp={'image':'jpg | png | gif', “文档”:“pdf | txt”, “音频”:“mp3 | wav”} 对于键,filetypes\u re\u exp.items中的值: self.assertEqualvalue,文件类型\u re[key]。模式 测试通过了。但可能是因为我从mediamanager.models模块导入了其他对象,所以此测试用例中的其他测试失败。不是所有的,只有两个很奇怪。编辑:一点也不奇怪。仅在测试文件重新加载和重新加载调用后运行的测试失败

问题 如何以以下方式“重新加载”模块mediamanager.models:

是否使用新设置评估文件类型? 从同一模型导入的所有其他对象是否仍不受影响? 我应该仅仅因为重新加载后代码变得不稳定而重写代码吗?我指的是mediamanager.models中的其他对象,它们在重新加载后没有通过测试?我读过一些关于重新加载模块的文章,通常这不是一个好主意


有没有更好的方法来定义模块级对象(如这个regexp)以使测试更容易?

有几种方法。不经意间:

# mediamanager/models.py

import re

from django.conf import settings

def get_filetypes_re(mm_filetypes=settings.MM_FILETYPES):
    filetypes_re = {}
    for key, exts in settings.MM_FILETYPES.items():
    filetypes_re[key] = re.compile(r'({})'.format('|'.join(exts)))
    return filetypes_re 
还有你的测试:

MM_FILETYPES={'image': ['jpg', 'png', 'gif'],
                        'document': ['pdf', 'txt'],
                        'audio': ['mp3', 'wav']})

def test_filetype_re(self):
    filetypes_re = mediamanager.models.get_filetypes_re(mm_filetypes=MM_FILETYPES)
    filetypes_re_exp = {'image': '(jpg|png|gif)',
                        'document': '(pdf|txt)',
                        'audio': '(mp3|wav)'}

    for key, value in filetypes_re_exp.items():
        self.assertEqual(value, filetypes_re[key].pattern)

有两种方法。不经意间:

# mediamanager/models.py

import re

from django.conf import settings

def get_filetypes_re(mm_filetypes=settings.MM_FILETYPES):
    filetypes_re = {}
    for key, exts in settings.MM_FILETYPES.items():
    filetypes_re[key] = re.compile(r'({})'.format('|'.join(exts)))
    return filetypes_re 
还有你的测试:

MM_FILETYPES={'image': ['jpg', 'png', 'gif'],
                        'document': ['pdf', 'txt'],
                        'audio': ['mp3', 'wav']})

def test_filetype_re(self):
    filetypes_re = mediamanager.models.get_filetypes_re(mm_filetypes=MM_FILETYPES)
    filetypes_re_exp = {'image': '(jpg|png|gif)',
                        'document': '(pdf|txt)',
                        'audio': '(mp3|wav)'}

    for key, value in filetypes_re_exp.items():
        self.assertEqual(value, filetypes_re[key].pattern)

您能再解释一下为什么需要重新加载模块吗?为什么要更改测试的第一个版本?这是因为用户自己定义MM_文件类型。因此,我不知道我应该测试什么。临时我使用decorator覆盖这些设置,但由于mediamanager.models已加载,因此使用旧设置评估文件类型。我需要将他重新加载到新设置生效。啊,好的-你需要清除一些东西-你问题中的第一块代码-这是来自你的settings.py吗?还是别的地方?其次,单元测试要做的就是检查mediamanager.models.filetypes是否与您期望的匹配。为什么?mediamanager是您的应用程序吗?否,settings.py是irelevant。每个设置的测试都应该通过,这就是我使用override_settings decorator创建已知输入的原因。在这个unittest中,只有这个方法test\u filetypes\u会检查filetypes\u re。其他方法检查mediamanager.models中的其他对象,这就是这些测试失败的原因。重新加载模块后,从该模块导入的所有对象仍指向旧对象。哪些旧对象?mediamanager.models有什么变化吗?您能再解释一下为什么需要重新加载模块吗?为什么要更改测试的第一个版本?这是因为用户自己定义MM_文件类型。因此,我不知道我应该测试什么。临时我使用decorator覆盖这些设置,但由于mediamanager.models已加载,因此使用旧设置评估文件类型。我需要将他重新加载到新设置生效。啊,好的-你需要清除一些东西-第一个块
您的问题中的代码数量-是否来自您的settings.py?还是别的地方?其次,单元测试要做的就是检查mediamanager.models.filetypes是否与您期望的匹配。为什么?mediamanager是您的应用程序吗?否,settings.py是irelevant。每个设置的测试都应该通过,这就是我使用override_settings decorator创建已知输入的原因。在这个unittest中,只有这个方法test\u filetypes\u会检查filetypes\u re。其他方法检查mediamanager.models中的其他对象,这就是这些测试失败的原因。重新加载模块后,从该模块导入的所有对象仍指向旧对象。哪些旧对象?mediamanager.models有什么变化吗?我也想到了这一点,但是:我正在编译这个regexp,所以我不必每次都编译它,这样可以节省一点时间。在我的模块上有更多的正则表达式。我真的怀疑你是否能注意到你将节省的微秒。但是如果你真的想进行微优化,你可以只记忆函数的返回值。哦,仅供参考,python缓存了最近几百个编译的正则表达式——我怀疑,即使是实现记忆化所需的六行代码也会在执行时间上产生可测量的差异。那样的话,你的回答对我来说是可以接受的。我只是想在模块顶部定义filetypes\u re=get\u filetypes\u re,但是如果python在内部缓存regexp,那么就没有必要了……谢谢!这比定义一个模块级变量要好:我也想到了这一点,但是:我正在编译这个regexp,所以我不必每次都编译它,这样可以节省一点时间。在我的模块上有更多的正则表达式。我真的怀疑你是否能注意到你将节省的微秒。但是如果你真的想进行微优化,你可以只记忆函数的返回值。哦,仅供参考,python缓存了最近几百个编译的正则表达式——我怀疑,即使是实现记忆化所需的六行代码也会在执行时间上产生可测量的差异。那样的话,你的回答对我来说是可以接受的。我只是想在模块顶部定义filetypes\u re=get\u filetypes\u re,但是如果python在内部缓存regexp,那么就没有必要了……谢谢!这比定义模块级变量要好: