Skip to content

Commit 785d9dc

Browse files
authored
fix(traceloop-sdk): avoid calling async json methods in JSONEncoder (#3968)
1 parent 25189ad commit 785d9dc

File tree

2 files changed

+59
-1
lines changed

2 files changed

+59
-1
lines changed

packages/traceloop-sdk/tests/test_workflows.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -496,3 +496,55 @@ def dataclass_workflow(data: TestDataClass):
496496
assert task_span.parent.span_id == workflow_span.context.span_id
497497
assert workflow_span.attributes[SpanAttributes.TRACELOOP_ENTITY_NAME] == "dataclass_workflow"
498498
assert task_span.attributes[SpanAttributes.TRACELOOP_ENTITY_NAME] == "dataclass_task"
499+
500+
501+
class FakeAsyncRequest:
502+
async def json(self):
503+
return {"ok": True}
504+
505+
506+
class FakeSyncRequest:
507+
def json(self):
508+
return {"ok": True}
509+
510+
511+
@pytest.mark.asyncio
512+
async def test_async_workflow_with_async_json_method_argument(exporter, recwarn):
513+
@workflow(name="request_workflow")
514+
async def request_workflow(request: FakeAsyncRequest):
515+
return {"ok": True}
516+
517+
await request_workflow(FakeAsyncRequest())
518+
519+
assert not any(
520+
w.category is RuntimeWarning and "was never awaited" in str(w.message)
521+
for w in recwarn
522+
)
523+
524+
spans = exporter.get_finished_spans()
525+
assert [span.name for span in spans] == ["request_workflow.workflow"]
526+
527+
workflow_span = spans[0]
528+
assert json.loads(workflow_span.attributes[SpanAttributes.TRACELOOP_ENTITY_INPUT]) == {
529+
"args": ["FakeAsyncRequest"],
530+
"kwargs": {},
531+
}
532+
assert json.loads(workflow_span.attributes[SpanAttributes.TRACELOOP_ENTITY_OUTPUT]) == {"ok": True}
533+
534+
535+
def test_workflow_with_sync_json_method_argument(exporter):
536+
@workflow(name="request_workflow")
537+
def request_workflow(request: FakeSyncRequest):
538+
return {"ok": True}
539+
540+
request_workflow(FakeSyncRequest())
541+
542+
spans = exporter.get_finished_spans()
543+
assert [span.name for span in spans] == ["request_workflow.workflow"]
544+
545+
workflow_span = spans[0]
546+
assert json.loads(workflow_span.attributes[SpanAttributes.TRACELOOP_ENTITY_INPUT]) == {
547+
"args": [{"ok": True}],
548+
"kwargs": {},
549+
}
550+
assert json.loads(workflow_span.attributes[SpanAttributes.TRACELOOP_ENTITY_OUTPUT]) == {"ok": True}

packages/traceloop-sdk/traceloop/sdk/utils/json_encoder.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import dataclasses
2+
import inspect
23
import json
34

45

@@ -15,7 +16,12 @@ def default(self, o):
1516
return o.to_json()
1617

1718
if hasattr(o, "json"):
18-
return o.json()
19+
json_method = o.json
20+
if callable(json_method) and not inspect.iscoroutinefunction(json_method):
21+
result = json_method()
22+
if not inspect.iscoroutine(result):
23+
return result
24+
result.close()
1925

2026
if hasattr(o, "__class__"):
2127
return o.__class__.__name__

0 commit comments

Comments
 (0)