You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何阻止pytest缓存动态修改并重新导入的模块?

问题:pytest参数化测试中towerlib动态加载Credential类失败

我用pytest测试依赖towerlib的代码,这个库的towerlib.entities.credential.py模块会动态添加属性,Credential类通过重新导入自身来查找对应类型的Credential子类。在REPL里直接跑e2e.prepare_and_run_e2e能正常返回结果,但用@pytest.mark.parametrize装饰的测试函数会抛出异常:'Could not dynamically load credential with type',具体报错是AttributeError: module 'towerlib.entities.credential' has no attribute 'NetworkCredential'。试过用-p no:cacheprovider参数运行pytest,没用。因为是需要调用外部系统的测试,不想用patch/mock绕过Credential类,也改不了towerlib的实现,想找pytest相关配置解决。


相关代码片段

towerlib中的Credential类实现

class Credential:  # pylint: disable=too-few-public-methods
    """Credential factory to handle the different credential types returned."""

    def __new__(cls, tower_instance, data):
        try:
            credential_type_name = tower_instance.get_credential_type_by_id(data.get('credential_type')).name
            credential_type_name = ''.join(credential_type_name.split())
            credential_type = f'{credential_type_name}Credential'
            credential_type_obj = getattr(importlib.import_module('towerlib.entities.credential'), credential_type)
            credential = credential_type_obj(tower_instance, data)
        except Exception:  # pylint: disable=broad-except
            LOGGER.exception(
                'Could not dynamically load credential with type : "%s", trying a generic one.', credential_type
            )
            credential = GenericCredential(tower_instance, data)
        return credential

我的pytest测试函数

@pytest.mark.parametrize("device", get_all_e2e_devices())
def test_e2e(device):
    results = e2e.prepare_and_run_e2e([device], None, None, False, True, True, False, True)
    ...

报错信息

ERROR    credentials:credential.py:189 Could not dynamically load credential with type : "NetworkCredential", trying a generic one.
Traceback (most recent call last):
  File "{my local path}\.venv\lib\site-packages\towerlib\entities\credential.py", line 186, in __new__
    credential_type_obj = getattr(importlib.import_module('towerlib.entities.credential'), credential_type)
AttributeError: module 'towerlib.entities.credential' has no attribute 'NetworkCredential'

解决方案

1. 修改pytest的模块导入模式

pytest默认的importmode=prepend会导致模块重复导入时状态不一致,改成append模式可以让模块导入行为和REPL保持一致:

  • 命令行执行:pytest --importmode=append
  • 配置文件(pytest.ini)设置:
[pytest]
importmode = append

2. 用fixture替代直接参数化

把设备列表的生成逻辑移到fixture中,延迟参数初始化时机,确保towerlib模块先完成加载:

@pytest.fixture(params=get_all_e2e_devices())
def device(request):
    return request.param

def test_e2e(device):
    results = e2e.prepare_and_run_e2e([device], None, None, False, True, True, False, True)
    ...

3. 预加载并强制刷新towerlib模块

在项目根目录的conftest.py中添加代码,提前加载并刷新credential模块,确保所有动态生成的子类都被注册:

# conftest.py
import importlib
import towerlib.entities.credential

# 强制触发模块内所有Credential子类的定义
importlib.reload(towerlib.entities.credential)

内容的提问来源于stack exchange,提问作者pythko

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 02:06:25