Skip to content

Commit 4a43322

Browse files
authored
fix(openapi): preserve acronyms in generated exception descriptions (#4921)
* fix(openapi): preserve acronyms in generated exception descriptions The pascal_case_to_text helper split before every capital letter, so exception names containing acronyms produced unreadable schema descriptions, e.g. InvalidAPIKeyError became "Invalid A P I Key Error". Split only where a lowercase letter or digit meets an uppercase letter, or where an uppercase run is followed by a new word, so consecutive capitals stay together and the same name now renders as "Invalid API Key Error". Fixes #4004 * refactor(openapi): convert word boundary pattern to a verbose regex
1 parent bd18fd4 commit 4a43322

2 files changed

Lines changed: 41 additions & 2 deletions

File tree

litestar/_openapi/responses.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,19 @@
4242

4343
__all__ = ("create_responses_for_handler",)
4444

45-
CAPITAL_LETTERS_PATTERN = re.compile(r"(?=[A-Z])")
45+
WORD_BOUNDARY_PATTERN = re.compile(
46+
r"""
47+
(?<=[a-z0-9])(?=[A-Z]) # a lowercase letter or digit, followed by an uppercase letter
48+
|
49+
(?<=[A-Z])(?=[A-Z][a-z]) # an uppercase run, followed by a new capitalized word
50+
""",
51+
re.VERBOSE,
52+
)
4653

4754

4855
def pascal_case_to_text(string: str) -> str:
4956
"""Given a 'PascalCased' string, return its split form- 'Pascal Cased'."""
50-
return " ".join(re.split(CAPITAL_LETTERS_PATTERN, string)).strip()
57+
return " ".join(re.split(WORD_BOUNDARY_PATTERN, string)).strip()
5158

5259

5360
def create_cookie_schema(cookie: Cookie) -> Schema:

tests/unit/test_openapi/test_responses.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from litestar._openapi.responses import (
1616
ResponseFactory,
1717
create_error_responses,
18+
pascal_case_to_text,
1819
)
1920
from litestar._openapi.schema_generation.plugins import openapi_schema_plugins
2021
from litestar.datastructures import Cookie, ResponseHeader
@@ -151,6 +152,37 @@ class AlternativePetException(HTTPException):
151152
assert schema.type
152153

153154

155+
@pytest.mark.parametrize(
156+
("string", "expected"),
157+
[
158+
("PetException", "Pet Exception"),
159+
("InvalidAPIKeyError", "Invalid API Key Error"),
160+
("HTTPException", "HTTP Exception"),
161+
("ValidationException", "Validation Exception"),
162+
("API", "API"),
163+
("Error", "Error"),
164+
("error", "error"),
165+
("HTTP404Error", "HTTP404 Error"),
166+
("Base64Decoder", "Base64 Decoder"),
167+
("", ""),
168+
],
169+
)
170+
def test_pascal_case_to_text(string: str, expected: str) -> None:
171+
assert pascal_case_to_text(string) == expected
172+
173+
174+
def test_create_error_responses_preserves_acronyms_in_description() -> None:
175+
class InvalidAPIKeyError(HTTPException):
176+
status_code = 401
177+
178+
_, response = next(create_error_responses(exceptions=[InvalidAPIKeyError]))
179+
180+
assert response.content
181+
schema = response.content[MediaType.JSON].schema
182+
assert isinstance(schema, Schema)
183+
assert schema.description == "Invalid API Key Error"
184+
185+
154186
def test_create_error_responses_with_non_http_status_code() -> None:
155187
class HouseNotFoundError(HTTPException):
156188
status_code: int = 420

0 commit comments

Comments
 (0)