Skip to main content
 首页 » 编程设计

Python——重新加载模块级对象

2025年05月04日14lexus

我想做什么

我正在尝试编写单元测试来检查我的正则表达式是否正确构建:

# mediamanager/models.py 
 
import re 
 
from django.conf import settings 
 
filetypes_re = {} 
for key, exts in settings.MM_FILETYPES.items(): 
    filetypes_re[key] = re.compile(r'({})'.format('|'.join(exts))) 

注意:实际上,我完全不确定我为什么要编写这个单元测试,因为这段代码不仅仅是直截了当的……但这不是重点。

如您所见,最终的正则表达式取决于变量 settings.MM_FILETYPES,它可以由用户设置。我需要测试特定的输入,对于这种情况,Django 提供了装饰器@override_settings 来临时覆盖设置值:

# mediamanager/tests.py 
 
import unittest 
from django.test.utils import override_settings 
from mediamanager.models import (filetypes_re, …)  # import everything we want to test 
 
class ModelsTestCase(unittest.TestCase): 
    @override_settings(MM_FILETYPES={'image': ['jpg', 'png', 'gif'], 
                                     'document': ['pdf', 'txt'], 
                                     'audio': ['mp3', 'wav']}) 
    def test_filetype_re(self): 
        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 在设置被覆盖之前加载,因此 filetypes_re 是使用旧设置编译的。我需要重新加载它(以某种方式)以使新设置生效。

问题

我以这种方式更改了单元测试:

@override_settings(MM_FILETYPES={'image': ['jpg', 'png', 'gif'], 
                                 'document': ['pdf', 'txt'], 
                                 'audio': ['mp3', 'wav']}) 
def test_filetype_re(self): 
    import mediamanager.models  # obtaining module object from sys.modules have the same result 
    reload(mediamanager.models) 
    filetypes_re = mediamanager.models.filetypes_re 
    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 模块中导入了其他对象,导致此测试用例中的其他测试失败。不是全部,只有两个(这很奇怪)。 编辑:一点也不奇怪。仅在 test_filetyes_re 和 reload() 调用后运行的测试失败。

问题

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

  1. filetypes_re 是否使用新设置进行评估?
  2. 从同一模型导入的所有其他对象不受影响?

我是否应该重写一段代码,因为它在重新加载后变得不稳定(我的意思是来自 mediamanager.models 的其他对象在重新加载后未通过测试)?我读过一些关于重新加载模块的文章,通常这不是一个好主意。

是否有更好的方法来定义模块级对象(例如此正则表达式)以简化测试?

请您参考如下方法:

有几种方法。离开我的头顶:

# 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)