Использование итерации/списка/генератора динамически загружаемых приспособлений pytestPython

Программы на Python
Ответить Пред. темаСлед. тема
Anonymous
 Использование итерации/списка/генератора динамически загружаемых приспособлений pytest

Сообщение Anonymous »

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

Код: Выделить всё

from pathlib import Path
import shutil

from pytest import CaptureFixture
import pytest

from .tests import testutils

FIXTURES_ROOT = Path(__file__).parent / "fixtures"
INBOX = Path(__file__).parent / "inbox"
CONVERTED = Path(__file__).parent / "converted"

class TestItem:

converted_dir: Path

def __init__(self, inbox_dir: Path):
self.inbox_dir = inbox_dir
self.converted_dir = CONVERTED / inbox_dir.name

def load_test_fixture(
name: str,
*,
exclusive: bool = False,
override_name: str | None = None,
match_filter: str | None = None,
cleanup_inbox: bool = False,
):
src = FIXTURES_ROOT / name
if not src.exists():
raise FileNotFoundError(
f"Fixture {name} not found. Does it exist in {FIXTURES_ROOT}?"
)
dst = INBOX / (override_name or name)
dst.mkdir(parents=True, exist_ok=True)

for f in src.glob("**/*"):
dst_f = dst / f.relative_to(src)
if f.is_file() and not dst_f.exists():
dst_f.parent.mkdir(parents=True, exist_ok=True)
shutil.copy(f, dst_f)

# if any files in dst are not in src, delete them
for f in dst.glob("**/*"):
src_f = src / f.relative_to(dst)
if f.is_file() and not src_f.exists():
f.unlink()

if exclusive or match_filter is not None:
testutils.set_match_filter(match_filter or name)

converted_dir = CONVERTED / (override_name or name)
shutil.rmtree(converted_dir, ignore_errors=True)

return TestItem(dst)
Это работает хорошо — фикстура загружается динамически, и я могу создать из нее кучу однострочных фикстур:

Код: Выделить всё

@pytest.fixture(scope="function")
def basic_fixture():
return load_test_fixture("basic_fixture", exclusive=True)

def test_converted_dir_exists(
basic_fixture: TestItem, capfd: CaptureFixture[str]
):
assert basic_fixture.converted_dir.exists()
Я также разработал загрузчик с несколькими приборами, который возвращает массив приборов:

Код: Выделить всё

def load_test_fixtures(
*names: str,
exclusive: bool = False,
override_names: list[str] | None = None,
match_filter: str | None = None,
):
if exclusive:
match_filter = match_filter or rf"^({'|'.join(override_names or names)})"

return [
load_test_fixture(name, override_name=override, match_filter=match_filter)
for (name, override) in zip(names, override_names or names)
]
Но теперь я хочу, чтобы загрузчик действовал как приспособление, где он может возвращать элемент, а затем убирать за собой. Это отлично работает для одного загрузчика:

Код: Выделить всё

def load_test_fixture(
name: str,
*,
exclusive: bool = False,
override_name: str | None = None,
match_filter: str | None = None,
cleanup_inbox: bool = False,
):
# ...
# instead of returning, yield the item

yield TestItem(dst)

if cleanup_inbox:
shutil.rmtree(dst, ignore_errors=True)

@pytest.fixture(scope="function")
def basic_fixture():
yield from load_test_fixture("basic_fixture", exclusive=True)
Но я не могу заставить его работать с мультизагрузчиком, потому что он возвращает либо генератор генераторов, либо список генераторов. Я также пытался преобразовать их в @pytest.fixtures, но, похоже, не могу заставить версию списка возвращать свои элементы и правильно ждать очистки после завершения теста, а в качестве фикстур я бы добавил проблема с передачей аргументов как косвенных или параметров (ew).

Код: Выделить всё

def load_test_fixtures(
*names: str,
exclusive: bool = False,
override_names: list[str] | None = None,
match_filter: str | None = None,
):
if exclusive:
match_filter = match_filter or rf"^({'|'.join(override_names or names)})"

yield from (
load_test_fixture(name, match_filter=match_filter, override_name=override)
for name, override in zip(names, override_names or names)
)
# tried all combinations of list, tuple, and yield here, as well as

# yield (next(load_test_fixture(name, match_filter=match_filter, override_name=override))
#    for name, override in zip(names, override_names or names)
Я даже пробовал это, это вроде работает, но не ждет окончания теста для запуска финализатора:

Код: Выделить всё

fixtures = []
for f in [
"basic_fixture",
"fancy_fixture",
"tasty_fixture",
"smart_fixture",
]:
fixtures.extend(
load_test_fixture(f, match_filter=match_filter, cleanup_inbox=True)
)
yield fixtures
(Если я передам здесь cleanup_inbox=True, файлы будут удалены перед запуском теста).

Подробнее здесь: https://stackoverflow.com/questions/783 ... t-fixtures
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение
  • Разница в показателях производительности с clang — использование генератора Ninja и генератора Visual Studio
    Anonymous » » в форуме C++
    0 Ответы
    34 Просмотры
    Последнее сообщение Anonymous
  • Совместно ли процессы используют разделы обычных динамически загружаемых библиотек, доступные только для чтения?
    Anonymous » » в форуме C++
    0 Ответы
    16 Просмотры
    Последнее сообщение Anonymous
  • Импорт типов в динамически загружаемых модулях
    Anonymous » » в форуме Python
    0 Ответы
    14 Просмотры
    Последнее сообщение Anonymous
  • Импорт типов в динамически загружаемых модулях
    Anonymous » » в форуме Python
    0 Ответы
    16 Просмотры
    Последнее сообщение Anonymous
  • Импорт типов в динамически загружаемых модулях
    Anonymous » » в форуме Python
    0 Ответы
    22 Просмотры
    Последнее сообщение Anonymous

Вернуться в «Python»