"""Shared helpers for UKO Layer 2 BDD step files. Provides a ``capture_error`` context manager that reduces the repeated try/except boilerplate for "negative-test" steps. Used by: - uko_l2_vocabulary_steps.py - uko_l2_detail_level_steps.py - uko_l2_coverage_ttl_steps.py - uko_l2_vocab_registry_steps.py """ from __future__ import annotations from collections.abc import Generator from contextlib import contextmanager from typing import TYPE_CHECKING if TYPE_CHECKING: from behave.runner import Context @contextmanager def capture_error( ctx: Context, *exc_types: type[BaseException], ) -> Generator[None]: """Run the body and capture any matching exception on ``ctx.error``. On success ``ctx.error`` is set to ``None``; on failure it is set to the caught exception instance. Usage:: with capture_error(ctx, ValidationError): VocabularyClass(uri="", label="Test") Args: ctx: Behave context (must support attribute assignment). *exc_types: One or more exception types to catch. Yields: Control to the step body. Note: This intentionally suppresses the caught exception so the subsequent ``@then`` step can inspect ``ctx.error``. This is a **test-infrastructure exemption** from CONTRIBUTING.md's "do not suppress errors" rule -- suppression is the entire purpose of negative-test capture in BDD step definitions. """ try: yield ctx.error = None # type: ignore[attr-defined] except exc_types as exc: ctx.error = exc # type: ignore[attr-defined]