简体   繁体   English

pytest 无法导入本地模块(改为导入内置模块)

[英]pytest failed to import local module (importing built-in module instead)

I have the following Python 2.7 simplified project structure:我有以下 Python 2.7 简化项目结构:

project/
  ├── libs/
  |     └── zipfile.py
  ├── tests/
  |     ├── __init__.py
  |     └── test_hello.py
  ├── hello.py
  └── main.py

I want this project to use the patched version of one of Python built-in modules (which in this example is zipfile ) located in libs .我希望该项目使用位于libs的 Python 内置模块之一(在本例中为zipfile )的修补版本。 Note that this is an external requirement, and I cannot change the project structure.请注意,这是外部要求,我无法更改项目结构。


Below are the simplified implementation of each file:下面是每个文件的简化实现:

libs/zipfile.py库/zipfile.py

def is_zipfile(filename):
    return "Patched zipfile called"

tests/test_hello.py测试/test_hello.py

from hello import hello

def test_hello():
    assert hello() == "Patched zipfile called"

hello.py你好.py

import os
import sys

libs_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "libs"))
if libs_path not in sys.path:
    sys.path.insert(1, libs_path)

import zipfile

def hello():
    print(zipfile.__file__)  # to check which zipfile module is imported
    result = zipfile.is_zipfile("some_path")
    return result

main.py主文件

from hello import hello

def main():
    print(hello())

if __name__ == "__main__":
    main()

When running the program directly ( python main.py ), I got the expected result:直接运行程序( python main.py )时,得到了预期的结果:

/home/project/libs/zipfile.pyc
Patched zipfile called

However, when running pytest with project as the working directory ( pytest -s ), it failed:但是,当以project作为工作目录( pytest -s )运行 pytest 时,它失败了:

/usr/lib/python2.7/zipfile.pyc
================================== FAILURES ===================================
_________________________________ test_hello __________________________________

    def test_hello():
>       assert hello() == "Patched zipfile called"
E       assert False == 'Patched zipfile called'
E        +  where False = hello()

tests/test_hello.py:4: AssertionError
========================== 1 failed in 0.13 seconds ===========================

I've tried a couple solutions presented in this SO post , such as running python -m pytest , but none has worked for me.我已经尝试了这篇 SO post 中提出的几个解决方案,例如运行python -m pytest ,但没有一个对我python -m pytest Is there a way to successfully run this test in a non-hacky way?有没有办法以非hacky的方式成功运行这个测试?

The reason your patched zipfile module is not being imported is it has already been imported before the test is started (likely by pytest or one of its dependencies)未导入修补的zipfile模块的原因是它在测试开始之前已经导入(可能是 pytest 或其依赖项之一)

I verified this by putting this at the top of hello.py :我通过将其放在hello.py的顶部来验证这hello.py

if 'zipfile' in sys.modules:
    raise AssertionError('zipfile already imported')

I then get:然后我得到:

$ ./venv/bin/python -mpytest tests
============================= test session starts ==============================
platform linux -- Python 3.6.7, pytest-4.3.0, py-1.8.0, pluggy-0.9.0
rootdir: /tmp/x, inifile:
collected 0 items / 1 errors                                                   

==================================== ERRORS ====================================
_____________________ ERROR collecting tests/test_hello.py _____________________
tests/test_hello.py:1: in <module>
    from hello import hello
hello.py:5: in <module>
    raise AssertionError('zipfile already imported')
E   AssertionError: zipfile already imported
!!!!!!!!!!!!!!!!!!! Interrupted: 1 errors during collection !!!!!!!!!!!!!!!!!!!!
=========================== 1 error in 0.14 seconds ============================

You could delete zipfile from sys.modules and then perhaps your copy would be the only one imported:您可以从sys.modules删除zipfile ,然后也许您的副本将是唯一导入的:

sys.modules.pop('zipfile', None)

That said, all of this seems like potentially a bad idea as anyone who has already imported that module will have access to the old zipfile and stubbing out stdlib implementation has high potential to break third party libraries which don't expect that.也就是说,所有这些似乎都可能是一个坏主意,因为任何已经导入该模块的人都可以访问旧的zipfile并且剔除 stdlib 实现很有可能破坏不期望的第三方库。

You might have ~slightly better luck by patching out individual methods on the zipfile module directly (using something like mock.patch.object(zipfile, 'fn', ...)通过直接修补zipfile模块上的各个方法(使用类似mock.patch.object(zipfile, 'fn', ...)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM