|
| 1 | +--- |
| 2 | +summary: Declare `typing-extensions` as core's runtime dependency so a bare `import lite_bootstrap` (no extras) works — the code uses it at runtime and pydantic requires `typing_extensions.TypedDict` on Python < 3.12, so genuine zero-dependency is not achievable while supporting 3.10/3.11. |
| 3 | +--- |
| 4 | + |
| 5 | +# Design: Declare the runtime `typing_extensions` core dependency |
| 6 | + |
| 7 | +## Summary |
| 8 | + |
| 9 | +`lite-bootstrap` core imports `typing_extensions` at runtime but never declared |
| 10 | +it, so a bare `pip install lite-bootstrap` + `import lite_bootstrap` (no extras) |
| 11 | +crashes with `ModuleNotFoundError: No module named 'typing_extensions'`. Declare |
| 12 | +`typing-extensions` as core's one dependency. (An attempt to instead *remove* the |
| 13 | +usage and keep core zero-dependency failed on Python < 3.12 — see below.) |
| 14 | + |
| 15 | +## Motivation |
| 16 | + |
| 17 | +Found by a clean-room install of the published `1.3.0` on a fresh 3.14t venv: |
| 18 | +core installed with **zero** declared dependencies (after orjson became opt-in), |
| 19 | +but `import lite_bootstrap` immediately raised on `base.py`'s top-level |
| 20 | +`import typing_extensions`. Pre-existing (bare `lite-bootstrap==1.2.3` fails |
| 21 | +identically — its only core dep, `orjson`, doesn't pull `typing_extensions`); |
| 22 | +every install with any extra masked it, since extras pull `typing_extensions` in |
| 23 | +transitively. 1.3.0's "zero-dependency core" claim was therefore false. |
| 24 | + |
| 25 | +Two runtime uses: |
| 26 | + |
| 27 | +- `base.py:4,24,30` — `typing_extensions.Self` return annotations. |
| 28 | +- `healthchecks_instrument.py:8` — `class HealthCheckTypedDict(typing_extensions.TypedDict, ...)`, |
| 29 | + used as a FastAPI response model (`health_check_handler() -> HealthCheckTypedDict`). |
| 30 | + |
| 31 | +## Design |
| 32 | + |
| 33 | +`pyproject.toml`: `dependencies = ["typing-extensions"]`. `typing-extensions` is |
| 34 | +pure Python, so core stays free-threaded-friendly; it is the leanest possible |
| 35 | +core (one small, ubiquitous dependency). |
| 36 | + |
| 37 | +## Rejected: remove the usage to keep core zero-dependency |
| 38 | + |
| 39 | +Attempted (deferred `Self` annotations via `from __future__ import annotations` + |
| 40 | +`TYPE_CHECKING`, and `typing.TypedDict` in healthchecks). It passed locally on |
| 41 | +3.12 and on an isolated 3.10 TypedDict construction, but **failed the CI matrix |
| 42 | +on 3.10 and 3.11**: pydantic rejects a stdlib `typing.TypedDict` model on Python |
| 43 | +< 3.12 — |
| 44 | + |
| 45 | +``` |
| 46 | +PydanticUserError: Please use `typing_extensions.TypedDict` instead of |
| 47 | +`typing.TypedDict` on Python < 3.12. |
| 48 | +``` |
| 49 | + |
| 50 | +Because `HealthCheckTypedDict` is a FastAPI/pydantic response model, it must be a |
| 51 | +`typing_extensions.TypedDict` for as long as 3.10/3.11 are supported. So core |
| 52 | +genuinely needs `typing_extensions` at runtime; declaring it is the honest fix. |
| 53 | + |
| 54 | +## Non-goals |
| 55 | + |
| 56 | +- Dropping Python 3.10/3.11 (which would make zero-dep achievable). Out of scope. |
| 57 | +- Amending the published `1.3.0` note (immutable); `1.3.1` states the corrected |
| 58 | + "one pure-Python dependency" story. |
| 59 | + |
| 60 | +## Testing |
| 61 | + |
| 62 | +- Clean-room bare install on 3.14t: `pip install lite-bootstrap` now pulls |
| 63 | + `typing-extensions`, and `import lite_bootstrap` + `FreeBootstrapper.bootstrap()` |
| 64 | + succeed. |
| 65 | +- `just test` 100% coverage on the full 3.10-3.14 matrix (the FastAPI healthcheck |
| 66 | + schema builds on every version); `just lint-ci` clean. |
| 67 | + |
| 68 | +## Risk |
| 69 | + |
| 70 | +- **None material.** Adds one pure-Python dependency that the code already |
| 71 | + required at runtime; strictly fixes a crash. `typing-extensions` is already |
| 72 | + present transitively in every non-bare install. |
0 commit comments