From 2af4f7b2e040f7b17dfc8e12e7cec74f78ee7097 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20H=C3=B8iby?= Date: Sun, 31 May 2026 00:16:31 +0200 Subject: [PATCH] fix(brc105): make PaymentMiddleware import lazy so core primitives work without Starlette Starlette is an optional extra (pip install "bsv-brc[starlette]"), but the brc105 package __init__ imported PaymentMiddleware unconditionally. That made ANY import from bsv_brc.brc105 -- including core 402 primitives like NonceManager, StaticPricing and BSVPayment -- raise ModuleNotFoundError: No module named 'starlette' when the extra was not installed. This also broke the documented local dev flow: `pip install -e '.[dev]'` (the dev extra does not include starlette) followed by `pytest` failed at collection (exit 2) because the brc105 test module imports from the package. Wrap the middleware import in try/except ModuleNotFoundError and substitute a placeholder that raises a clear, actionable ImportError on use. No dependency changes; behaviour with Starlette installed is unchanged. Verified locally (Python 3.13): - without starlette: `from bsv_brc.brc105 import NonceManager` now succeeds and `PaymentMiddleware()` raises a clear ImportError; pytest -> 123 passed, 6 skipped (was: collection error / exit 2) - with starlette installed: pytest -> 136 passed (unchanged) Co-Authored-By: Claude Opus 4.8 (1M context) --- src/bsv_brc/brc105/__init__.py | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/bsv_brc/brc105/__init__.py b/src/bsv_brc/brc105/__init__.py index 3d198ae..312902e 100644 --- a/src/bsv_brc/brc105/__init__.py +++ b/src/bsv_brc/brc105/__init__.py @@ -22,7 +22,26 @@ ) from bsv_brc.brc105.nonce import NonceManager from bsv_brc.brc105.challenge import create_challenge, parse_challenge_headers -from bsv_brc.brc105.middleware import PaymentMiddleware + +# PaymentMiddleware depends on Starlette, which is an optional extra +# (`pip install "bsv-brc[starlette]"`). Import it lazily so the core 402 +# primitives above remain usable without Starlette installed. +try: + from bsv_brc.brc105.middleware import PaymentMiddleware +except ModuleNotFoundError as _exc: # pragma: no cover - only without the extra + + class _MissingPaymentMiddleware: + """Placeholder raising a clear error when Starlette is not installed.""" + + _err = _exc + + def __init__(self, *_args, **_kwargs): + raise ImportError( + "PaymentMiddleware requires Starlette. " + 'Install it with: pip install "bsv-brc[starlette]"' + ) from self._err + + PaymentMiddleware = _MissingPaymentMiddleware # type: ignore[assignment,misc] __all__ = [ "PaymentChallenge",