- requirements: openpyxl==3.1.5, pyxlsb==1.0.10, xlrd==2.0.2, et_xmlfile==2.0.0 (транзитивная) - tests/fixtures_helpers.py, conftest: фикстура fixtures_dir, параметризация osv_file/synthetic_file, skip маркера fixtures - pyproject: mypy ignore_missing_imports для openpyxl/xlrd/pyxlsb, disallow_untyped_defs для src.parser.* Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012vJkmBGKKqMoEMzvsXG3y2
87 lines
3.3 KiB
Python
87 lines
3.3 KiB
Python
"""Общие фикстуры тестов."""
|
||
|
||
import os
|
||
from collections.abc import Callable
|
||
from pathlib import Path
|
||
|
||
import pytest
|
||
from fixtures_helpers import fixtures_skip_reason, osv_fixture_files, resolve_fixtures_dir, synthetic_files
|
||
|
||
from src.core.config import Settings
|
||
|
||
# Переменные, которые читает Settings: убираются из окружения процесса, чтобы тест видел только свой файл
|
||
_SETTINGS_ENV_PREFIXES = (
|
||
"OPENBAO__",
|
||
"SERVER__",
|
||
"DEBUG",
|
||
"ROOT_PATH",
|
||
"VERSION",
|
||
"SERVICE_NAME",
|
||
"NATS_ENABLED",
|
||
"WORKER_CONCURRENCY",
|
||
"PUBLISH_RETRIES",
|
||
"DONE_CACHE_SIZE",
|
||
)
|
||
|
||
# Минимальное окружение spec «Старт с минимальным окружением»: MinIO, адрес NATS и DEBUG; без seed/jwt, БД и SMB
|
||
MINIMAL_ENV = """\
|
||
DEBUG=true
|
||
OPENBAO__MINIO__MINIO_URL=localhost:9000
|
||
OPENBAO__MINIO__MINIO_ADMIN_LOGIN=minioadmin
|
||
OPENBAO__MINIO__MINIO_ADMIN_PASSWORD=minioadmin
|
||
OPENBAO__MINIO__MINIO_BUCKET=arm-ka
|
||
OPENBAO__NATS__NATS_URL=nats://localhost:4222
|
||
"""
|
||
|
||
|
||
@pytest.fixture
|
||
def minimal_settings(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> Callable[[str], Settings]:
|
||
"""Фабрика Settings только из временного `.env` с `MINIMAL_ENV` и строками `extra` (окружение процесса скрыто)."""
|
||
for name in list(os.environ):
|
||
if name.upper().startswith(_SETTINGS_ENV_PREFIXES):
|
||
monkeypatch.delenv(name)
|
||
|
||
def build(extra: str = "") -> Settings:
|
||
env_file = tmp_path / ".env"
|
||
env_file.write_text(MINIMAL_ENV + extra, encoding="utf-8")
|
||
return Settings(_env_file=env_file) # type: ignore[call-arg]
|
||
|
||
return build
|
||
|
||
|
||
@pytest.fixture(scope="session")
|
||
def fixtures_dir() -> Path:
|
||
"""Каталог `../fixtures`; тест пропускается с причиной, если каталога нет."""
|
||
reason = fixtures_skip_reason()
|
||
if reason is not None:
|
||
pytest.skip(reason)
|
||
return resolve_fixtures_dir()
|
||
|
||
|
||
def pytest_generate_tests(metafunc: pytest.Metafunc) -> None:
|
||
"""Параметры `osv_file` (реальные ОСВ) и `synthetic_file` (синтетика); без каталога — один параметр со skip."""
|
||
sources = {"osv_file": osv_fixture_files, "synthetic_file": synthetic_files}
|
||
for argname, listing in sources.items():
|
||
if argname not in metafunc.fixturenames:
|
||
continue
|
||
reason = fixtures_skip_reason()
|
||
if reason is not None:
|
||
metafunc.parametrize(
|
||
argname, [pytest.param(None, marks=pytest.mark.skip(reason=reason))], ids=["нет-фикстур"]
|
||
)
|
||
continue
|
||
root = resolve_fixtures_dir()
|
||
files = listing(root)
|
||
metafunc.parametrize(argname, files, ids=[path.relative_to(root).as_posix() for path in files])
|
||
|
||
|
||
def pytest_collection_modifyitems(config: pytest.Config, items: list[pytest.Item]) -> None:
|
||
"""Тесты с маркером `fixtures` пропускаются, если каталог фикстур недоступен."""
|
||
reason = fixtures_skip_reason()
|
||
if reason is None:
|
||
return
|
||
skip = pytest.mark.skip(reason=reason)
|
||
for item in items:
|
||
if item.get_closest_marker("fixtures"):
|
||
item.add_marker(skip)
|