Files
breakshaft/tests/test_ctxmanager.py
Qwen Code Assistant ca605001b3 feat: масштабное улучшение системы обработки ошибок и тестирования
Основные изменения:
- Добавлена иерархия исключений (17 классов) с кодами ошибок и контекстом
- Улучшена обработка ошибок: детальные сообщения с подсказками
- Добавлено 24 теста для экстремальных случаев (комбинаторика, циклы, async)
- Добавлено 23 теста для системы обработки ошибок
- Исправлен баг с optional-аргументами в renderer.py
- Обновлены импорты в тестах (src.breakshaft → breakshaft)

Документация:
- ERROR_DESIGN.md — проектирование системы ошибок
- COMMUTATIVITY_DESIGN.md — анализ проблемы некоммутативности (10 вариантов решений)

Файлы:
- src/breakshaft/exceptions.py (новый) — модуль исключений
- tests/test_error_handling.py (новый) — тесты ошибок
- tests/test_extreme_cases.py (новый) — экстремальные кейсы

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-03-28 13:42:04 +00:00

87 lines
2.0 KiB
Python

from contextlib import contextmanager, asynccontextmanager
from dataclasses import dataclass
from typing import Any, Generator, AsyncGenerator
import pytest
from breakshaft.convertor import ConvRepo
pytest_plugins = ('pytest_asyncio',)
@dataclass
class A:
a: int
@dataclass
class B:
b: float
def test_sync_ctxmanager():
repo = ConvRepo()
@repo.mark_injector()
def b_to_a(b: B) -> A:
return A(int(b.b))
@repo.mark_injector()
def a_to_b(a: A) -> B:
return B(float(a.a))
int_to_a_finalized = [False]
@repo.mark_injector()
@contextmanager
def int_to_a(i: int) -> Generator[A, Any, None]:
yield A(i)
int_to_a_finalized[0] = True
def consumer(dep: A) -> int:
return dep.a
fn1 = repo.get_conversion((B,), consumer, force_commutative=True, force_async=False, allow_async=False)
dep = fn1(B(42.1))
assert dep == 42
assert not int_to_a_finalized[0]
fn2 = repo.get_conversion((int,), consumer, force_commutative=True, force_async=False, allow_async=False)
dep = fn2(123)
assert dep == 123
assert int_to_a_finalized[0]
@pytest.mark.asyncio
async def test_async_ctxmanager():
repo = ConvRepo()
@repo.mark_injector()
def b_to_a(b: B) -> A:
return A(int(b.b))
@repo.mark_injector()
def a_to_b(a: A) -> B:
return B(float(a.a))
int_to_a_finalized = [False]
@repo.mark_injector()
@asynccontextmanager
async def int_to_a(i: int) -> AsyncGenerator[A, Any]:
yield A(i)
int_to_a_finalized[0] = True
def consumer(dep: A) -> int:
return dep.a
fn1 = repo.get_conversion((B,), consumer, force_commutative=True, force_async=False, allow_async=True)
dep = fn1(B(42.1))
assert dep == 42
assert not int_to_a_finalized[0]
fn2 = repo.get_conversion((int,), consumer, force_commutative=True, force_async=False, allow_async=True)
dep = await fn2(123)
assert dep == 123
assert int_to_a_finalized[0]