Files
python-repositories/tests/unit/adapters_test.py
T
Brian Bjarke JensenandCursor 5e32787b90
Code Quality Pipeline / code-quality (pull_request) Successful in 52s
PR Title Check / check-title (pull_request) Successful in 6s
Test Python Package / test (pull_request) Successful in 1m3s
Add config and client injection with test reorganization.
Introduce typed config objects, optional adapter injection, and .env loading to simplify testing while preserving env-based defaults for production usage.

Co-authored-by: Cursor <[email protected]>
2026-07-05 21:34:14 +02:00

120 lines
4.0 KiB
Python

"""Unit tests for lazy adapter loading in adapters subpackage."""
from __future__ import annotations
import builtins
import importlib
import os
import subprocess
import sys
from collections.abc import Callable, Mapping, Sequence
from pathlib import Path
from types import ModuleType
from unittest.mock import patch
import pytest
import python_repositories
_ROOT = Path(__file__).resolve().parents[2]
def _block_backend_import(blocked_prefix: str) -> Callable[..., ModuleType]:
real_import = builtins.__import__
def fake_import(
name: str,
globals: Mapping[str, object] | None = None,
locals: Mapping[str, object] | None = None,
fromlist: Sequence[str] = (),
level: int = 0,
) -> ModuleType:
if name == blocked_prefix or name.startswith(f"{blocked_prefix}."):
raise ImportError(f"No module named '{name}'")
return real_import(name, globals, locals, fromlist, level)
return fake_import
def test_base_import_does_not_load_adapters() -> None:
"""Base package import does not eagerly load backend adapter modules."""
script = """
import sys
from python_repositories import JsonRepositoryInterface
assert JsonRepositoryInterface is not None
assert "python_repositories.adapters.redis_adapter" not in sys.modules
assert "python_repositories.adapters.minio_adapter" not in sys.modules
"""
result = subprocess.run(
[sys.executable, "-c", script],
cwd=_ROOT,
env={**os.environ, "PYTHONPATH": str(_ROOT)},
capture_output=True,
text=True,
)
assert result.returncode == 0, result.stderr or result.stdout
def test_lazy_adapter_load_succeeds_when_extra_present() -> None:
"""Adapters load when their optional dependencies are installed."""
from python_repositories import MinioAdapter, RedisAdapter
assert RedisAdapter.__name__ == "RedisAdapter"
assert MinioAdapter.__name__ == "MinioAdapter"
def test_redis_adapter_import_error_without_extra() -> None:
"""Missing redis extra raises ImportError with install hint."""
import python_repositories.adapters.redis_adapter as redis_adapter_module
with patch.object(builtins, "__import__", new=_block_backend_import("redis")):
with pytest.raises(ImportError, match=r"python-repositories\[redis\]"):
importlib.reload(redis_adapter_module)
importlib.reload(redis_adapter_module)
def test_minio_adapter_import_error_without_extra() -> None:
"""Missing minio extra raises ImportError with install hint."""
import python_repositories.adapters.minio_adapter as minio_adapter_module
with patch.object(builtins, "__import__", new=_block_backend_import("minio")):
with pytest.raises(ImportError, match=r"python-repositories\[minio\]"):
importlib.reload(minio_adapter_module)
importlib.reload(minio_adapter_module)
def test_top_level_lazy_import_propagates_redis_import_error() -> None:
"""Top-level RedisAdapter access surfaces adapter import errors."""
with patch(
"importlib.import_module",
side_effect=ImportError(
"Redis support requires the redis extra. "
"Install with: pip install python-repositories[redis]"
),
):
with pytest.raises(ImportError, match=r"python-repositories\[redis\]"):
_ = python_repositories.RedisAdapter
def test_top_level_lazy_import_propagates_minio_import_error() -> None:
"""Top-level MinioAdapter access surfaces adapter import errors."""
with patch(
"importlib.import_module",
side_effect=ImportError(
"MinIO support requires the minio extra. "
"Install with: pip install python-repositories[minio]"
),
):
with pytest.raises(ImportError, match=r"python-repositories\[minio\]"):
_ = python_repositories.MinioAdapter
def test_adapters_subpackage_lazy_import_succeeds() -> None:
"""Adapter subpackage imports delegate to the same lazy loader."""
from python_repositories.adapters import RedisAdapter
assert RedisAdapter.__name__ == "RedisAdapter"