66from typing import Any
77
88import pytest
9- from opentelemetry .proto .collector .trace .v1 .trace_service_pb2 import (
10- ExportTraceServiceRequest ,
11- )
129from opentelemetry .proto .common .v1 .common_pb2 import (
1310 AnyValue ,
1411 InstrumentationScope ,
@@ -105,8 +102,8 @@ def create_test_span():
105102 return span
106103
107104
108- def create_test_export_request (project_id = "test_project" ):
109- """Create a test ExportTraceServiceRequest with one span."""
105+ def create_test_export_request (project_id = "test_project" ) -> tsi . OTelExportReq :
106+ """Create a test OTelExportReq with one span."""
110107 span = create_test_span ()
111108
112109 # Create instrumentation scope
@@ -131,15 +128,17 @@ def create_test_export_request(project_id="test_project"):
131128 resource_spans .resource .CopyFrom (resource )
132129 resource_spans .scope_spans .append (scope_spans )
133130
134- # Create traces data
135- traces_data = TracesData ()
136- traces_data . resource_spans . append ( resource_spans )
137-
138- # Create export request
139- request = ExportTraceServiceRequest ()
140- request . resource_spans . append ( resource_spans )
131+ # Create processed resource spans
132+ processed_span = tsi . ProcessedResourceSpans (
133+ entity = "test-entity" ,
134+ project = "test-project" ,
135+ run_id = None ,
136+ resource_spans = resource_spans ,
137+ )
141138
142- return tsi .OtelExportReq (project_id = project_id , traces = request , wb_user_id = None )
139+ return tsi .OTelExportReq (
140+ project_id = project_id , processed_spans = [processed_span ], wb_user_id = None
141+ )
143142
144143
145144def test_otel_export_clickhouse (client : weave_client .WeaveClient ):
@@ -152,7 +151,7 @@ def test_otel_export_clickhouse(client: weave_client.WeaveClient):
152151 # Export the otel traces
153152 response = client .server .otel_export (export_req )
154153 # Verify the response is of the correct type
155- assert isinstance (response , tsi .OtelExportRes )
154+ assert isinstance (response , tsi .OTelExportRes )
156155
157156 # Query the calls
158157 res = client .server .calls_query (
@@ -164,7 +163,7 @@ def test_otel_export_clickhouse(client: weave_client.WeaveClient):
164163 assert len (res .calls ) == 1
165164
166165 call = res .calls [0 ]
167- export_span = export_req .traces . resource_spans [0 ].scope_spans [0 ].spans [0 ]
166+ export_span = export_req .processed_spans [0 ]. resource_spans .scope_spans [0 ].spans [0 ]
168167 decoded_trace = hexlify (export_span .trace_id ).decode ("ascii" )
169168 decoded_span = hexlify (export_span .span_id ).decode ("ascii" )
170169
@@ -213,8 +212,10 @@ def test_otel_export_with_turn_and_thread(client: weave_client.WeaveClient):
213212 export_req .wb_user_id = "abcd123"
214213
215214 # Add turn and thread attributes to the span
215+ # Materialize processed_spans to avoid iterator exhaustion
216216 test_thread_id = str (uuid .uuid4 ())
217- span = export_req .traces .resource_spans [0 ].scope_spans [0 ].spans [0 ]
217+ processed_spans_list = export_req .processed_spans
218+ span = processed_spans_list [0 ].resource_spans .scope_spans [0 ].spans [0 ]
218219
219220 kv_is_turn = KeyValue ()
220221 kv_is_turn .key = "wandb.is_turn"
@@ -226,9 +227,11 @@ def test_otel_export_with_turn_and_thread(client: weave_client.WeaveClient):
226227 kv_thread .value .string_value = test_thread_id
227228 span .attributes .append (kv_thread )
228229
230+ export_req .processed_spans = processed_spans_list
231+
229232 # Export the otel traces
230233 response = client .server .otel_export (export_req )
231- assert isinstance (response , tsi .OtelExportRes )
234+ assert isinstance (response , tsi .OTelExportRes )
232235
233236 # Query the calls
234237 res = client .server .calls_query (
@@ -263,16 +266,20 @@ def test_otel_export_with_turn_no_thread(client: weave_client.WeaveClient):
263266 export_req .wb_user_id = "abcd123"
264267
265268 # Add only is_turn attribute (no thread_id)
266- span = export_req .traces .resource_spans [0 ].scope_spans [0 ].spans [0 ]
269+ # Materialize processed_spans to avoid iterator exhaustion
270+ processed_spans_list = export_req .processed_spans
271+ span = processed_spans_list [0 ].resource_spans .scope_spans [0 ].spans [0 ]
267272
268273 kv_is_turn = KeyValue ()
269274 kv_is_turn .key = "wandb.is_turn"
270275 kv_is_turn .value .bool_value = True
271276 span .attributes .append (kv_is_turn )
272277
278+ export_req .processed_spans = processed_spans_list
279+
273280 # Export the otel traces
274281 response = client .server .otel_export (export_req )
275- assert isinstance (response , tsi .OtelExportRes )
282+ assert isinstance (response , tsi .OTelExportRes )
276283
277284 # Query the calls
278285 res = client .server .calls_query (
@@ -462,8 +469,9 @@ def test_span_to_call_with_turn_and_thread(self):
462469 def test_traces_data_from_proto (self ):
463470 """Test converting protobuf TracesData to Python TracesData."""
464471 export_req = create_test_export_request ()
472+ resource_spans_list = [ps .resource_spans for ps in export_req .processed_spans ]
465473 traces_data = PyTracesData .from_proto (
466- TracesData (resource_spans = export_req . traces . resource_spans )
474+ TracesData (resource_spans = resource_spans_list )
467475 )
468476
469477 assert len (traces_data .resource_spans ) == 1
@@ -1160,7 +1168,12 @@ def test_opentelemetry_cost_calculation(self, client: weave_client.WeaveClient):
11601168
11611169 # Create export request
11621170 export_req = create_test_export_request (project_id = project_id )
1163- export_req .traces .resource_spans [0 ].scope_spans [0 ].spans [0 ].CopyFrom (span_gpt4 )
1171+ # Materialize processed_spans to avoid iterator exhaustion
1172+ processed_spans_list = export_req .processed_spans
1173+ processed_spans_list [0 ].resource_spans .scope_spans [0 ].spans [0 ].CopyFrom (
1174+ span_gpt4
1175+ )
1176+ export_req .processed_spans = processed_spans_list
11641177 export_req .wb_user_id = "test_user"
11651178
11661179 # Export the trace
@@ -1444,7 +1457,11 @@ def test_otel_export_partial_success_on_attribute_conflict(
14441457 export_req .wb_user_id = "abcd123"
14451458
14461459 # Good span (already present at index 0)
1447- good_span = export_req .traces .resource_spans [0 ].scope_spans [0 ].spans [0 ]
1460+ # Materialize processed_spans to avoid iterator exhaustion
1461+ processed_spans_list = export_req .processed_spans
1462+
1463+ # Good span (already present at index 0)
1464+ good_span = processed_spans_list [0 ].resource_spans .scope_spans [0 ].spans [0 ]
14481465 good_span_id = hexlify (good_span .span_id ).decode ("ascii" )
14491466
14501467 # Add a conflicting span to the same batch
@@ -1461,12 +1478,13 @@ def test_otel_export_partial_success_on_attribute_conflict(
14611478 kv_child .value .string_value = "Hello"
14621479 bad_span .attributes .append (kv_child )
14631480
1464- export_req .traces .resource_spans [0 ].scope_spans [0 ].spans .append (bad_span )
1481+ processed_spans_list [0 ].resource_spans .scope_spans [0 ].spans .append (bad_span )
1482+ export_req .processed_spans = processed_spans_list
14651483 bad_span_id = hexlify (bad_span .span_id ).decode ("ascii" )
14661484
14671485 # Export
14681486 res = client .server .otel_export (export_req )
1469- assert isinstance (res , tsi .OtelExportRes )
1487+ assert isinstance (res , tsi .OTelExportRes )
14701488 assert res .partial_success is not None
14711489 assert res .partial_success .rejected_spans == 1
14721490 # Error message should mention the conflicting key and guidance
@@ -1522,7 +1540,9 @@ def test_otel_span_wandb_attributes_and_data_routing(
15221540 export_req .wb_user_id = "abcd123"
15231541
15241542 # Get the span to add custom attributes
1525- span = export_req .traces .resource_spans [0 ].scope_spans [0 ].spans [0 ]
1543+ # Materialize processed_spans to avoid iterator exhaustion
1544+ processed_spans_list = export_req .processed_spans
1545+ span = processed_spans_list [0 ].resource_spans .scope_spans [0 ].spans [0 ]
15261546
15271547 # Clear default test attributes
15281548 del span .attributes [:]
@@ -1591,9 +1611,11 @@ def test_otel_span_wandb_attributes_and_data_routing(
15911611 kv_provider .value .string_value = "openai"
15921612 span .attributes .append (kv_provider )
15931613
1614+ export_req .processed_spans = processed_spans_list
1615+
15941616 # Export the OTEL traces
15951617 response = client .server .otel_export (export_req )
1596- assert isinstance (response , tsi .OtelExportRes )
1618+ assert isinstance (response , tsi .OTelExportRes )
15971619
15981620 # Query the calls
15991621 res = client .server .calls_query (
0 commit comments