Files
2026-07-13 13:32:05 +08:00

75 lines
2.2 KiB
Python

import pytest
from concurrent.futures import ThreadPoolExecutor
from contextvars import copy_context
from deepeval.tracing import observe, trace_manager
from deepeval.tracing.context import current_span_context, current_trace_context
@observe(type="tool")
def child_function():
return "child result"
@observe(type="agent")
def parent_with_plain_executor():
executor = ThreadPoolExecutor(max_workers=1)
future = executor.submit(child_function)
future.result()
executor.shutdown(wait=True)
return "done"
@observe(type="agent")
def parent_with_copy_context():
ctx = copy_context()
executor = ThreadPoolExecutor(max_workers=1)
future = executor.submit(ctx.run, child_function)
future.result()
executor.shutdown(wait=True)
return "done"
@pytest.fixture(autouse=True)
def clean_trace_state():
trace_manager.clear_traces()
trace_manager.tracing_enabled = False
current_span_context.set(None)
current_trace_context.set(None)
yield
trace_manager.clear_traces()
trace_manager.tracing_enabled = True
current_span_context.set(None)
current_trace_context.set(None)
def test_threadpool_without_copy_context_creates_two_traces(completed_traces):
"""Without copy_context, the child @observe function in a ThreadPoolExecutor
creates a separate trace because ContextVar values don't propagate to
new threads."""
parent_with_plain_executor()
assert (
len(completed_traces) == 2
), f"Expected 2 traces (parent + orphaned child), got {len(completed_traces)}"
def test_threadpool_with_copy_context_creates_one_trace(completed_traces):
"""With copy_context, the child @observe function in a ThreadPoolExecutor
correctly attaches to the parent trace because ContextVar values are
propagated."""
parent_with_copy_context()
assert (
len(completed_traces) == 1
), f"Expected 1 trace (child nested under parent), got {len(completed_traces)}"
the_trace = completed_traces[0]
assert len(the_trace.root_spans) == 1, "Expected exactly 1 root span"
root_span = the_trace.root_spans[0]
assert (
len(root_span.children) == 1
), "Expected the child function as a child span of the root"
assert root_span.children[0].name == "child_function"