Skip to content

Commit 62858e2

Browse files
fschlzclaude
andcommitted
fix: render SDK-surface list/get as structured JSON
json.dumps(pydantic_model, default=str) collapses the model to a single repr string, so `list`/`get` on the default SDK surface printed unreadable output while REST printed proper JSON. Add a _dump() helper that unwraps pydantic results via model_dump(mode="json") and passes REST dicts through. Regression tests cover both surfaces. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 124e7e6 commit 62858e2

2 files changed

Lines changed: 26 additions & 2 deletions

File tree

scripts/online_eval_rules/create_online_eval_rules.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,15 @@ def _dispatch_create(args, dry_run: bool) -> int:
134134
return 0
135135

136136

137+
def _dump(result) -> str:
138+
"""JSON-print a result from either surface. REST returns a dict; the SDK returns a
139+
pydantic model, which json.dumps can't serialise (default=str would collapse it to a
140+
single repr string), so unwrap it with model_dump first."""
141+
if hasattr(result, "model_dump"):
142+
result = result.model_dump(mode="json")
143+
return json.dumps(result, indent=2, default=str)
144+
145+
137146
def _dispatch_manage(args, dry_run: bool) -> int:
138147
if dry_run:
139148
print(f"[DRY RUN] would '{args.command}' via {getattr(args, 'surface', 'sdk')} "
@@ -149,12 +158,12 @@ def _dispatch_manage(args, dry_run: bool) -> int:
149158
if args.command == "list":
150159
result = (via_sdk(client, "list", project_id=project_id) if args.surface == "sdk"
151160
else via_rest("list", project_id=project_id))
152-
print(json.dumps(result, indent=2, default=str))
161+
print(_dump(result))
153162
return 0
154163
if args.command == "get":
155164
result = (via_sdk(client, "get", rule_id=args.id, project_id=project_id) if args.surface == "sdk"
156165
else via_rest("get", rule_id=args.id, project_id=project_id))
157-
print(json.dumps(result, indent=2, default=str))
166+
print(_dump(result))
158167
return 0
159168
if args.command == "update":
160169
current = via_rest("get", rule_id=args.id, project_id=project_id)

scripts/online_eval_rules/test_create_online_eval_rules.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,21 @@ def test_build_sdk_request_returns_correct_variant():
182182
assert req.code.schema_[0].name == "relevance_score"
183183

184184

185+
def test_dump_unwraps_pydantic_model_to_structured_json():
186+
# SDK-surface list/get return pydantic models; _dump must emit structured JSON,
187+
# not a single repr string (json.dumps(model, default=str) would do the latter).
188+
req = cli.build_sdk_request(
189+
cli.build_payload(cli.RULE_LLM_JUDGE, name="r", project_id="pid",
190+
sampling_rate=1.0, model="gpt-4o")
191+
)
192+
parsed = json.loads(cli._dump(req))
193+
assert isinstance(parsed, dict) and parsed["name"] == "r"
194+
195+
196+
def test_dump_passes_through_rest_dict():
197+
assert json.loads(cli._dump({"content": [], "ok": True})) == {"content": [], "ok": True}
198+
199+
185200
class _FakeEvaluators:
186201
def __init__(self):
187202
self.created = None

0 commit comments

Comments
 (0)