Skip to content

Commit b6db4c1

Browse files
jopemachineclaude
andcommitted
fix(BA-6003): address CI failures post-main-rebase
* Sort imports in tests/unit/common/configs/{test_meta,test_generator,test_inspector}.py (ruff I001). * Expand the catch tuple in tests/unit/common/test_typed_validators.py to also accept BackendAISchemaValidationFailed alongside ValidationError and TypeError — HostPortPair now inherits BackendAISchema so model_validate raises the wrapped exception. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 60ab51b commit b6db4c1

6 files changed

Lines changed: 110 additions & 7 deletions

File tree

backend.ai-openid-plugin

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Subproject commit 025e0849b2fd87f5344ce6f403f0223500c9bab7
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
"""Simulate the validation-error log path without hitting the server.
2+
3+
Goal: show what an operator would see in mgr logs when
4+
``BackendAISchema.model_validate`` fails and the result propagates
5+
through ``convert_validation_error`` -> exception middleware.
6+
7+
Run::
8+
9+
PY=dist/export/python/virtualenvs/python-default/3.13.7/bin/python
10+
PYTHONPATH=src $PY scripts/show_validation_log_format.py
11+
"""
12+
13+
from __future__ import annotations
14+
15+
import logging
16+
17+
from ai.backend.common.api_handlers import convert_validation_error
18+
from ai.backend.common.exception import (
19+
BackendAIError,
20+
BackendAISchemaValidationFailed,
21+
InvalidAPIParameters,
22+
)
23+
from ai.backend.common.types import BackendAISchema
24+
25+
logging.basicConfig(
26+
level=logging.WARNING,
27+
format="%(asctime)s %(levelname)s %(name)s [%(process)d] %(message)s",
28+
)
29+
log = logging.getLogger("ai.backend.manager.api.rest.middleware.exception")
30+
31+
32+
class Address(BackendAISchema):
33+
city: str
34+
zipcode: int
35+
36+
37+
class User(BackendAISchema):
38+
name: str
39+
age: int
40+
address: Address
41+
42+
43+
@convert_validation_error
44+
def parse_body(model: type[BackendAISchema], body: dict) -> BackendAISchema:
45+
"""Stand-in for ``BodyParam.from_body`` — same decorator wrapping."""
46+
return model.model_validate(body)
47+
48+
49+
def middleware_log(ex: BackendAIError, *, method: str, endpoint: str) -> None:
50+
"""Same call shape the real exception middleware uses."""
51+
log.warning(
52+
"client error raised inside handlers: (%s %s): %s",
53+
method,
54+
endpoint,
55+
repr(ex),
56+
)
57+
58+
59+
def banner(title: str) -> None:
60+
print()
61+
print("=" * 78)
62+
print(title)
63+
print("=" * 78)
64+
65+
66+
# === Scenario 1: schema with multiple nested missing fields ===============
67+
banner("[1] body={} for User → caught by BackendAISchema.model_validate")
68+
try:
69+
User.model_validate({})
70+
except BackendAISchemaValidationFailed as e:
71+
print('e!!', e)
72+
73+
74+
# === Scenario 2: same body going through convert_validation_error =========
75+
banner("[2] body={} for User → caught by BodyParam (convert_validation_error)")
76+
try:
77+
parse_body(User, {})
78+
except InvalidAPIParameters as e:
79+
print(f"-- type: {type(e).__name__} (← wrapped, not BackendAISchemaValidationFailed)")
80+
print(f"-- status_code: {e.status_code}")
81+
print(f"-- error_type: {e.error_type}")
82+
print(f"-- error_title: {e.error_title}")
83+
print(f"-- extra_msg (str):\n{e.extra_msg}")
84+
print(f"-- extra_data: {e.extra_data!r}")
85+
print()
86+
print("-- middleware log line would be:")
87+
middleware_log(e, method="POST", endpoint="/v2/users")
88+
89+
90+
# === Scenario 3: partial body with nested + sibling errors ================
91+
banner("[3] body with mixed errors going through convert_validation_error")
92+
bad_body = {
93+
"name": "alice",
94+
"age": "not-an-int",
95+
"address": {"city": "Seoul"},
96+
}
97+
try:
98+
parse_body(User, bad_body)
99+
except InvalidAPIParameters as e:
100+
print(f"-- type: {type(e).__name__}")
101+
print(f"-- extra_msg (str):\n{e.extra_msg}")
102+
print(f"-- extra_data: {e.extra_data!r}")
103+
print()
104+
print("-- middleware log line would be:")
105+
middleware_log(e, method="POST", endpoint="/v2/users")

tests/unit/common/configs/test_generator.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@
66
import pytest
77
from pydantic import Field
88

9-
from ai.backend.common.types import BackendAISchema
10-
119
from ai.backend.common.configs.generator import (
1210
BinarySizeFormatter,
1311
CompositeFormatter,
@@ -29,6 +27,7 @@
2927
ConfigEnvironment,
3028
ConfigExample,
3129
)
30+
from ai.backend.common.types import BackendAISchema
3231

3332

3433
class TestFieldVisibility:

tests/unit/common/configs/test_inspector.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@
55
import pytest
66
from pydantic import Field
77

8-
from ai.backend.common.types import BackendAISchema
9-
108
from ai.backend.common.configs.inspector import (
119
ConfigInspector,
1210
FieldDocumentation,
@@ -19,6 +17,7 @@
1917
ConfigEnvironment,
2018
ConfigExample,
2119
)
20+
from ai.backend.common.types import BackendAISchema
2221

2322

2423
class TestFieldTypeInfo:

tests/unit/common/configs/test_meta.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@
55
import pytest
66
from pydantic import Field
77

8-
from ai.backend.common.types import BackendAISchema
9-
108
from ai.backend.common.meta import (
119
BackendAIAPIMeta,
1210
BackendAIConfigMeta,
@@ -18,6 +16,7 @@
1816
get_field_meta,
1917
get_field_type,
2018
)
19+
from ai.backend.common.types import BackendAISchema
2120

2221

2322
class TestConfigExample:

tests/unit/common/test_typed_validators.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,5 +64,5 @@ def test_hostport_pair_valid(
6464
],
6565
)
6666
def test_hostport_pair_invalid(input: str | list[str] | dict[str, str] | int) -> None:
67-
with pytest.raises((ValidationError, TypeError)):
67+
with pytest.raises((BackendAISchemaValidationFailed, ValidationError, TypeError)):
6868
HostPortPair.model_validate(input)

0 commit comments

Comments
 (0)