Skip to content

Commit 65845e0

Browse files
lesnik512claude
andauthored
fix: declare typing-extensions as core's runtime dependency (#158)
Bare `pip install lite-bootstrap` + `import lite_bootstrap` (no extras) crashed on undeclared typing_extensions: base.py uses `typing_extensions.Self` and healthchecks_instrument.py's TypedDict is a FastAPI response model that pydantic requires be a `typing_extensions.TypedDict` on Python < 3.12 (stdlib typing.TypedDict is rejected there). So genuine zero-dependency core is not achievable while supporting 3.10/3.11 — declare typing-extensions (pure Python, free-threaded-friendly). Pre-existing (bare 1.2.3 failed identically); surfaced by a clean-room 3.14t install of published 1.3.0. Ships as 1.3.1. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent f84ffbe commit 65845e0

3 files changed

Lines changed: 108 additions & 1 deletion

File tree

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
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.

planning/releases/1.3.1.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# lite-bootstrap 1.3.1 — fix bare-install import (`typing-extensions`)
2+
3+
**1.3.1 is a patch release. Fully backward compatible with 1.3.0.**
4+
5+
## Bug fixes
6+
7+
- **Bare `import lite_bootstrap` no longer crashes on a missing
8+
`typing_extensions`.** Core uses `typing_extensions` at runtime (a `Self`
9+
return annotation, and a `TypedDict` FastAPI response model that pydantic
10+
requires be a `typing_extensions.TypedDict` on Python < 3.12) but never
11+
declared it, so `pip install lite-bootstrap` with no extras followed by
12+
`import lite_bootstrap` raised `ModuleNotFoundError: No module named
13+
'typing_extensions'`. `typing-extensions` is now declared as core's single
14+
dependency. It is pure Python, so free-threaded support is unchanged, and this
15+
is the leanest possible core.
16+
17+
This corrects 1.3.0's note, which called core "zero-dependency": the code
18+
genuinely needs `typing_extensions` while Python 3.10/3.11 are supported. The
19+
bug was pre-existing (bare `1.2.3` failed the same way); every install with any
20+
extra masked it, because extras pull `typing_extensions` in transitively.
21+
22+
## Backwards compatibility
23+
24+
Fully compatible with 1.3.0. No API or configuration changes; the only
25+
difference is that a bare-core install now resolves `typing-extensions` and
26+
imports cleanly.
27+
28+
## References
29+
30+
- `planning/changes/2026-07-19.03-core-zero-dep-typing-extensions.md`

pyproject.toml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,12 @@ classifiers = [
2020
"Topic :: Software Development :: Libraries",
2121
]
2222
version = "0"
23-
dependencies = []
23+
dependencies = [
24+
# Runtime use: `typing_extensions.Self` (base.py) and `typing_extensions.TypedDict`
25+
# (healthchecks) — the latter is required by pydantic/FastAPI on Python < 3.12
26+
# (`typing.TypedDict` is rejected there). Pure Python, so ft-friendly.
27+
"typing-extensions",
28+
]
2429

2530
[project.urls]
2631
Homepage = "https://lite-bootstrap.modern-python.org"

0 commit comments

Comments
 (0)