Pytest не удалось импортировать локальный модуль (вместо этого импортируется встроенный модуль) - PullRequest
1 голос
/ 09 марта 2019

У меня есть следующая упрощенная структура проекта Python 2.7:

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

Я хочу, чтобы этот проект использовал исправленную версию одного из встроенных модулей Python (который в этом примере zipfile), расположенный в libs. Обратите внимание, что это внешнее требование, и я не могу изменить структуру проекта.


Ниже приведена упрощенная реализация каждого файла:

ЛИЭС / zipfile.py

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

Тесты / test_hello.py

from hello import hello

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

hello.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()

При непосредственном запуске программы (python main.py) я получил ожидаемый результат:

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

Однако при запуске pytest с project в качестве рабочего каталога (pytest -s) произошел сбой:

/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 ===========================

Я пробовал пару решений, представленных в этом посте SO , например, запуск python -m pytest, но ни одно из них не помогло мне. Есть ли способ успешно запустить этот тест не хакерским способом?

1 Ответ

1 голос
/ 09 марта 2019

Причина, по которой ваш исправленный zipfile модуль не импортируется, состоит в том, что он уже был импортирован до запуска теста (вероятно, с помощью pytest или одной из его зависимостей)

Я подтвердил это, поместив его наtop hello.py:

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

Затем я получаю:

$ ./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 ============================

Вы можете удалить zipfile из sys.modules, и тогда, возможно, ваша копия будет единственной импортированной:

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

Тем не менее, все это кажется потенциально плохой идеей, поскольку любой, кто уже импортировал этот модуль, будет иметь доступ к старому zipfile, а заглушка реализации stdlib имеет большой потенциал для взлома третьей стороны.библиотеки, которые этого не ожидают.

Возможно, вам немного повезет, если вы будете напрямую исправлять отдельные методы модуля zipfile (например, mock.patch.object(zipfile, 'fn', ...)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...