Бэкпорт importlib_resources не совместим с pyfakefs? - PullRequest
1 голос
/ 05 февраля 2020

Я реорганизую библиотеку для использования importlib.resources для python 3.7+. Я использую бэкпорт importlib_resources для совместимости python 3.6. Код работает для питонов 3.6-3.8. Тем не менее, тесты pytest, использующие pyfakefs, проваливаются на 3.6. В условиях тестирования путь, возвращаемый при использовании importlib_resources, искажается (но в «реальных» условиях они возвращаются правильно).

Минимальный пример: у меня есть следующая структура библиотеки:

mypackage
├── mypackage
│   ├── __init__.py
│   ├── bin
│   │   └── __init__.py
│   └── find_bin.py
└── tests
    └── test_find_bin.py

В самой библиотеке в папке bin содержатся двоичные файлы (плюс пустой __init__). Код в другом месте библиотеки нуждается в пути к нему. find_bin.py демонстрирует функцию, которая возвращает путь:

import sys
if sys.version_info >= (3, 7):
    from importlib import resources
else:
    import importlib_resources as resources

import mypackage.bin


def find_bin():
    init_path_context = resources.path(mypackage.bin, '__init__.py')
    with init_path_context as p:
        init_path = p
    bin_path = init_path.parent
    return bin_path

Тест pytest test_find_bin.py:

import pathlib

from mypackage.find_bin import find_bin


def test_findbin(fs):
    test_bin = (pathlib.Path(__file__)
                .resolve()
                .parent.parent
                .joinpath('mypackage', 'bin'))
    print('test bin is ', test_bin)
    expected_bin = find_bin()
    print('expected bin is ', expected_bin)
    assert not expected_bin.exists()
    print('test creating fakefs ', test_bin)
    fs.create_dir(test_bin)
    assert expected_bin.exists()

Python 3.7+ работает с тестами, как и ожидалось. В python 3.6 путь ожидаемого_бина искажен:

test bin is  /Users/geoffreysametz/Documents/mypackage/mypackage/bin  # correct
expected bin is  /var/folders/bv/m5cg5cp15t38sh8rxx244hp00000gn/T  # ?!?!?!

Я попытался отследить выполнение функции find_bin, и он длинный и запутанный. Однако я видел, что importlib_resources использует класс python FakeFilesystem. Моя гипотеза состоит в том, что проблема возникает из-за того, что importlib_resources и pytest одновременно используют поддельные файловые системы.

Верна ли моя гипотеза? Есть ли обходной путь для получения pytest для тестирования кода, который использует importlib_resources?

1 Ответ

1 голос
/ 05 февраля 2020

Поддельная файловая система в pyfakefs пуста при запуске теста (за исключением пути к временному файлу, необходимого для модуля tempfile), поэтому, если вы хотите получить доступ к любым файлам в файловой системе real в вашем тесте вам нужно сопоставить их с фальшивой файловой системой :

def test_findbin(fs):
    test_bin = (pathlib.Path(__file__)
                .resolve()
                .parent.parent
                .joinpath('mypackage', 'bin'))
    fs.add_real_directory(test_bin)
...

В вашем реальном тесте вы заранее не знаете путь, поэтому вам нужно добавить некоторый родительский путь, который Вы знаете, чтобы содержать свои ресурсы. Подкаталоги и файлы будут прочитаны и скопированы в поддельную файловую систему при доступе.

Что касается поведения вашего теста в Python 3.6: код в contextlib_package сначала проверяет, является ли (правильный) путь существует, и если его нет (как он проверяет в поддельной файловой системе, он не существует), он создает временный файл, в который он пытается скопировать некоторые данные - таким образом, временный путь в ваших выходных данных.

В Python 3.8 кажется, что он не проверяет существование пути, он просто создает Path объект с правильного пути. В любом случае это может привести к сбою в тот момент, когда вы попытаетесь получить доступ к некоторым ресурсам по этому пути, так как они не существуют в поддельной файловой системе, поэтому в этом случае вам также необходимо отобразить реальную файловую систему.

(скопировано и немного адаптирован из ответа в pyfakefs вопрос )

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