Commit fe874de
fix(openapi): use exact-match dedup in default_operation_id_creator
`default_operation_id_creator` builds an operationId by concatenating
title-cased path components, skipping a component if it's already
present via `component.title() not in components_namespace` — a
substring check against the concatenated string, not an exact-match
check against individual components.
This causes false collisions: for path components `["users", "user"]`,
"User" is a substring of the already-accumulated "Users", so the
"user" component is silently dropped, producing the same operationId
("UsersGetHandler") as a route whose only component is `["users"]`.
Two structurally different routes can end up with identical
operationIds, which OpenAPI requires to be unique
(test_routes_with_different_paths_should_generate_unique_operation_ids
already encodes this invariant, just not for this substring case).
Fix: track seen component titles in a set and check membership there
instead of doing a substring check against the concatenated namespace
string. This preserves the original intent (skip an exact-duplicate
component, e.g. when a router prefix repeats a literal path segment)
without falsely dropping components that merely share a substring.
How verified: reproduced the collision directly against
default_operation_id_creator with ["users"] vs ["users", "user"])
producing the same id; added a regression test
(test_default_operation_id_creator_does_not_collide_on_component_substring)
confirmed failing before the fix (AssertionError: 'UsersGetHandler' !=
'UsersGetHandler'); applied the fix; confirmed all 23 tests in
test_path_item.py and the full 262-test tests/unit/test_openapi/ suite
pass. mypy clean, pre-commit clean (ruff, unasyncd, typos).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>1 parent 4a43322 commit fe874de
2 files changed
Lines changed: 19 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
39 | 39 | | |
40 | 40 | | |
41 | 41 | | |
| 42 | + | |
42 | 43 | | |
43 | | - | |
44 | | - | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
45 | 48 | | |
46 | 49 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
129 | 129 | | |
130 | 130 | | |
131 | 131 | | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
132 | 146 | | |
133 | 147 | | |
134 | 148 | | |
| |||
0 commit comments