fastapi: fix AttributeError on partially matched routes with FastAPI 0.137 included routers (#4700)
* fastapi: handle FastAPI 0.137 _IncludedRouter routes FastAPI 0.137 changed ``app.routes`` from a flat list into a tree that nests ``include_router()`` routes under ``_IncludedRouter`` nodes. These nodes have no ``path`` attribute, so ``_get_route_details()`` raised ``AttributeError`` when resolving the route for any included route. Detect these nodes via their ``effective_route_contexts()`` and match the flattened contexts directly. This avoids the crash, reports the full templated route, and (by not calling ``_IncludedRouter.matches()``) avoids re-deriving the request scope. Fixes #4699 Assisted-by: Claude Opus 4.8 * fastapi: test route details for include_router routes Add a regression test asserting that a request to an ``include_router()``-added route reports the templated ``http.route`` and does not raise ``AttributeError`` on FastAPI 0.137+. Assisted-by: Claude Opus 4.8 * fastapi: bump tested FastAPI to 0.137.1 Pin the test dependencies to FastAPI 0.137.1 and the Starlette, pydantic and anyio versions it requires, so the suite exercises the 0.137 route tree. Assisted-by: Claude Opus 4.8 * fastapi: flatten included routes to dedupe route matching Addresses review feedback: the _IncludedRouter branch repeated the same Match.FULL/Match.PARTIAL handling as the regular-route path. Extract the expansion into a _flatten_routes() generator that yields effective route contexts for _IncludedRouter nodes and the route itself otherwise, so _get_route_details() runs a single match-and-extract loop over a uniform list of candidates. No behavior change; 105 tests pass on FastAPI 0.137.1. Assisted-by: Claude Opus 4.8 * fastapi: use public iter_route_contexts() to flatten routes FastAPI 0.137.2 added the public iter_route_contexts() helper for exactly the "walk the routes to find a match" use case, flattening include_router() trees (the 0.137 _IncludedRouter nodes) into RouteContext objects that expose matches() and the templated path. Prefer it over reaching into the private _IncludedRouter.effective_route_contexts() / _EffectiveRouteContext internals. _flatten_routes() now uses iter_route_contexts() when available and falls back to the previous behavior otherwise, so FastAPI 0.137.0/0.137.1 (which have _IncludedRouter but not the public helper) and versions before 0.137 (plain routes) keep working. The single match/extract loop is unchanged. Bump the tested FastAPI to 0.137.2 (starlette stays at 1.3.1). Verified 105 passed on 0.137.2 (public path), 0.137.1 (effective_route_contexts fallback), and 0.126.0 (plain-routes fallback). Assisted-by: Claude Opus 4.8 * Rework test-requirements to test multiple versions * Update workflows * fastapi: rename changelog fragment to PR number The changelog check requires the fragment to be named after the PR number (.changelog/<PR_NUMBER>.<type>); rename 4699.fixed -> 4700.fixed. * Try to please requirements for pypy --------- Co-authored-by: Riccardo Magliocchetti <riccardo.magliocchetti@gmail.com>
K
Kshitiz Jain committed
5b79cbdfc7e5362cfa95b7abaf412fad23ae2248
Parent: a5081cd
Committed by GitHub <noreply@github.com>
on 6/22/2026, 7:09:38 AM