Skip to content

Commit 5f26797

Browse files
committed
compat, making mypy happy
1 parent fea3b9b commit 5f26797

7 files changed

Lines changed: 144 additions & 22 deletions

File tree

sentry_sdk/api.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
LogLevelStr,
3838
SamplingContext,
3939
)
40+
from sentry_sdk.traces import StreamedSpan
4041
from sentry_sdk.tracing import Span, TransactionKwargs
4142

4243
T = TypeVar("T")
@@ -409,7 +410,9 @@ def set_measurement(name: str, value: float, unit: "MeasurementUnit" = "") -> No
409410
transaction.set_measurement(name, value, unit)
410411

411412

412-
def get_current_span(scope: "Optional[Scope]" = None) -> "Optional[Span]":
413+
def get_current_span(
414+
scope: "Optional[Scope]" = None,
415+
) -> "Optional[Union[Span, StreamedSpan]]":
413416
"""
414417
Returns the currently active span if there is one running, otherwise `None`
415418
"""
@@ -525,6 +528,16 @@ def update_current_span(
525528
if current_span is None:
526529
return
527530

531+
if isinstance(current_span, StreamedSpan):
532+
warnings.warn(
533+
"The `update_current_span` API isn't available in streaming mode. "
534+
"Retrieve the current span with get_current_span() and use its API "
535+
"directly.",
536+
DeprecationWarning,
537+
stacklevel=2,
538+
)
539+
return
540+
528541
if op is not None:
529542
current_span.op = op
530543

sentry_sdk/feature_flags.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import copy
22
import sentry_sdk
33
from sentry_sdk._lru_cache import LRUCache
4+
from sentry_sdk.tracing import Span
45
from threading import Lock
56

67
from typing import TYPE_CHECKING, Any
@@ -61,5 +62,5 @@ def add_feature_flag(flag: str, result: bool) -> None:
6162
flags.set(flag, result)
6263

6364
span = sentry_sdk.get_current_span()
64-
if span:
65+
if span and isinstance(span, Span):
6566
span.set_flag(f"flag.evaluation.{flag}", result)

sentry_sdk/scope.py

Lines changed: 55 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -584,7 +584,7 @@ def get_traceparent(self, *args: "Any", **kwargs: "Any") -> "Optional[str]":
584584

585585
# If we have an active span, return traceparent from there
586586
if has_tracing_enabled(client.options) and self.span is not None:
587-
return self.span.to_traceparent()
587+
return self.span._to_traceparent()
588588

589589
# else return traceparent from the propagation context
590590
return self.get_active_propagation_context().to_traceparent()
@@ -598,7 +598,7 @@ def get_baggage(self, *args: "Any", **kwargs: "Any") -> "Optional[Baggage]":
598598

599599
# If we have an active span, return baggage from there
600600
if has_tracing_enabled(client.options) and self.span is not None:
601-
return self.span.to_baggage()
601+
return self.span._to_baggage()
602602

603603
# else return baggage from the propagation context
604604
return self.get_active_propagation_context().get_baggage()
@@ -608,7 +608,7 @@ def get_trace_context(self) -> "Dict[str, Any]":
608608
Returns the Sentry "trace" context from the Propagation Context.
609609
"""
610610
if has_tracing_enabled(self.get_client().options) and self._span is not None:
611-
return self._span.get_trace_context()
611+
return self._span._get_trace_context()
612612

613613
# if we are tracing externally (otel), those values take precedence
614614
external_propagation_context = get_external_propagation_context()
@@ -673,7 +673,7 @@ def iter_trace_propagation_headers(
673673
span = span or self.span
674674

675675
if has_tracing_enabled(client.options) and span is not None:
676-
for header in span.iter_headers():
676+
for header in span._iter_headers():
677677
yield header
678678
elif has_external_propagation_context():
679679
# when we have an external_propagation_context (otlp)
@@ -720,7 +720,7 @@ def clear(self) -> None:
720720
self.clear_breadcrumbs()
721721
self._should_capture: bool = True
722722

723-
self._span: "Optional[Span]" = None
723+
self._span: "Optional[Union[Span, StreamedSpan]]" = None
724724
self._session: "Optional[Session]" = None
725725
self._force_auto_session_tracking: "Optional[bool]" = None
726726

@@ -774,6 +774,14 @@ def transaction(self) -> "Any":
774774
if self._span is None:
775775
return None
776776

777+
if isinstance(self._span, StreamedSpan):
778+
warnings.warn(
779+
"Scope.transaction is not available in streaming mode.",
780+
DeprecationWarning,
781+
stacklevel=2,
782+
)
783+
return None
784+
777785
# there is an orphan span on the scope
778786
if self._span.containing_transaction is None:
779787
return None
@@ -803,17 +811,39 @@ def transaction(self, value: "Any") -> None:
803811
"Assigning to scope.transaction directly is deprecated: use scope.set_transaction_name() instead."
804812
)
805813
self._transaction = value
806-
if self._span and self._span.containing_transaction:
807-
self._span.containing_transaction.name = value
814+
if self._span:
815+
if isinstance(self._span, StreamedSpan):
816+
warnings.warn(
817+
"Scope.transaction is not available in streaming mode.",
818+
DeprecationWarning,
819+
stacklevel=2,
820+
)
821+
return None
822+
823+
if self._span.containing_transaction:
824+
self._span.containing_transaction.name = value
808825

809826
def set_transaction_name(self, name: str, source: "Optional[str]" = None) -> None:
810827
"""Set the transaction name and optionally the transaction source."""
811828
self._transaction = name
829+
if self._span:
830+
if isinstance(self._span, NoOpStreamedSpan):
831+
return
832+
833+
elif isinstance(self._span, StreamedSpan):
834+
self._span._segment.name = name
835+
if source:
836+
self._span._segment.set_attribute(
837+
"sentry.span.source", getattr(source, "value", source)
838+
)
839+
840+
elif self._span.containing_transaction:
841+
self._span.containing_transaction.name = name
842+
if source:
843+
self._span.containing_transaction.source = source
812844

813-
if self._span and self._span.containing_transaction:
814-
self._span.containing_transaction.name = name
815-
if source:
816-
self._span.containing_transaction.source = source
845+
if source:
846+
self._transaction_info["source"] = source
817847

818848
if source:
819849
self._transaction_info["source"] = source
@@ -836,12 +866,12 @@ def set_user(self, value: "Optional[Dict[str, Any]]") -> None:
836866
session.update(user=value)
837867

838868
@property
839-
def span(self) -> "Optional[Span]":
869+
def span(self) -> "Optional[Union[Span, StreamedSpan]]":
840870
"""Get/set current tracing span or transaction."""
841871
return self._span
842872

843873
@span.setter
844-
def span(self, span: "Optional[Span]") -> None:
874+
def span(self, span: "Optional[Union[Span, StreamedSpan]]") -> None:
845875
self._span = span
846876
# XXX: this differs from the implementation in JS, there Scope.setSpan
847877
# does not set Scope._transactionName.
@@ -1150,6 +1180,15 @@ def start_span(
11501180
be removed in the next major version. Going forward, it should only
11511181
be used by the SDK itself.
11521182
"""
1183+
client = sentry_sdk.get_client()
1184+
if has_span_streaming_enabled(client.options):
1185+
warnings.warn(
1186+
"Scope.start_span is not available in streaming mode.",
1187+
DeprecationWarning,
1188+
stacklevel=2,
1189+
)
1190+
return NoOpSpan()
1191+
11531192
if kwargs.get("description") is not None:
11541193
warnings.warn(
11551194
"The `description` parameter is deprecated. Please use `name` instead.",
@@ -1169,6 +1208,9 @@ def start_span(
11691208

11701209
# get current span or transaction
11711210
span = self.span or self.get_isolation_scope().span
1211+
if isinstance(span, StreamedSpan):
1212+
# make mypy happy
1213+
return NoOpSpan()
11721214

11731215
if span is None:
11741216
# New spans get the `trace_id` from the scope

sentry_sdk/traces.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,7 @@ def finish(self, end_timestamp: "Optional[Union[float, datetime]]" = None) -> No
332332
def _start(self) -> None:
333333
if self._active:
334334
old_span = self._scope.span
335-
self._scope.span = self # type: ignore
335+
self._scope.span = self
336336
self._previous_span_on_scope = old_span
337337

338338
def _end(self, end_timestamp: "Optional[Union[float, datetime]]" = None) -> None:
@@ -563,7 +563,7 @@ def _start(self) -> None:
563563
return
564564

565565
old_span = self._scope.span
566-
self._scope.span = self # type: ignore
566+
self._scope.span = self
567567
self._previous_span_on_scope = old_span
568568

569569
def _end(self, end_timestamp: "Optional[Union[float, datetime]]" = None) -> None:

sentry_sdk/tracing.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -771,6 +771,12 @@ def update_active_thread(self) -> None:
771771
thread_id, thread_name = get_current_thread_meta()
772772
self.set_thread(thread_id, thread_name)
773773

774+
# Private aliases matching StreamedSpan's private API
775+
_to_traceparent = to_traceparent
776+
_to_baggage = to_baggage
777+
_iter_headers = iter_headers
778+
_get_trace_context = get_trace_context
779+
774780

775781
class Transaction(Span):
776782
"""The Transaction is the root element that holds all the spans
@@ -1243,6 +1249,8 @@ def _set_initial_sampling_decision(
12431249
)
12441250
)
12451251

1252+
_get_baggage = get_baggage
1253+
12461254

12471255
class NoOpSpan(Span):
12481256
def __repr__(self) -> str:
@@ -1324,6 +1332,13 @@ def _set_initial_sampling_decision(
13241332
) -> None:
13251333
pass
13261334

1335+
# Private aliases matching StreamedSpan's private API
1336+
_to_traceparent = to_traceparent
1337+
_to_baggage = to_baggage
1338+
_get_baggage = get_baggage
1339+
_iter_headers = iter_headers
1340+
_get_trace_context = get_trace_context
1341+
13271342

13281343
if TYPE_CHECKING:
13291344

sentry_sdk/tracing_utils.py

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -935,6 +935,14 @@ async def async_wrapper(*args: "Any", **kwargs: "Any") -> "Any":
935935
)
936936
return await f(*args, **kwargs)
937937

938+
if isinstance(current_span, StreamedSpan):
939+
warnings.warn(
940+
"Use the @sentry_sdk.traces.trace decorator in span streaming mode.",
941+
DeprecationWarning,
942+
stacklevel=2,
943+
)
944+
return await f(*args, **kwargs)
945+
938946
span_op = op or _get_span_op(template)
939947
function_name = name or qualname_from_function(f) or ""
940948
span_name = _get_span_name(template, function_name, kwargs)
@@ -972,6 +980,14 @@ def sync_wrapper(*args: "Any", **kwargs: "Any") -> "Any":
972980
)
973981
return f(*args, **kwargs)
974982

983+
if isinstance(current_span, StreamedSpan):
984+
warnings.warn(
985+
"Use the @sentry_sdk.traces.trace decorator in span streaming mode.",
986+
DeprecationWarning,
987+
stacklevel=2,
988+
)
989+
return f(*args, **kwargs)
990+
975991
span_op = op or _get_span_op(template)
976992
function_name = name or qualname_from_function(f) or ""
977993
span_name = _get_span_name(template, function_name, kwargs)
@@ -1072,7 +1088,9 @@ def sync_wrapper(*args: "Any", **kwargs: "Any") -> "Any":
10721088
return span_decorator
10731089

10741090

1075-
def get_current_span(scope: "Optional[sentry_sdk.Scope]" = None) -> "Optional[Span]":
1091+
def get_current_span(
1092+
scope: "Optional[sentry_sdk.Scope]" = None,
1093+
) -> "Optional[Union[Span, StreamedSpan]]":
10761094
"""
10771095
Returns the currently active span if there is one running, otherwise `None`
10781096
"""
@@ -1081,16 +1099,24 @@ def get_current_span(scope: "Optional[sentry_sdk.Scope]" = None) -> "Optional[Sp
10811099
return current_span
10821100

10831101

1084-
def set_span_errored(span: "Optional[Span]" = None) -> None:
1102+
def set_span_errored(span: "Optional[Union[Span, StreamedSpan]]" = None) -> None:
10851103
"""
10861104
Set the status of the current or given span to INTERNAL_ERROR.
10871105
Also sets the status of the transaction (root span) to INTERNAL_ERROR.
10881106
"""
1107+
from sentry_sdk.traces import StreamedSpan, SpanStatus
1108+
10891109
span = span or get_current_span()
1110+
10901111
if span is not None:
1091-
span.set_status(SPANSTATUS.INTERNAL_ERROR)
1092-
if span.containing_transaction is not None:
1093-
span.containing_transaction.set_status(SPANSTATUS.INTERNAL_ERROR)
1112+
if isinstance(span, Span):
1113+
span.set_status(SPANSTATUS.INTERNAL_ERROR)
1114+
if span.containing_transaction is not None:
1115+
span.containing_transaction.set_status(SPANSTATUS.INTERNAL_ERROR)
1116+
elif isinstance(span, StreamedSpan):
1117+
span.status = SpanStatus.ERROR
1118+
if span._segment is not None:
1119+
span._segment.status = SpanStatus.ERROR
10941120

10951121

10961122
def _generate_sample_rand(

tests/tracing/test_span_streaming.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -678,6 +678,31 @@ def test_continue_trace_no_sample_rand(sentry_init, capture_envelopes):
678678
assert segment["trace_id"] == trace_id
679679

680680

681+
def test_outgoing_traceparent_and_baggage(sentry_init, capture_envelopes):
682+
sentry_init(
683+
traces_sample_rate=1.0,
684+
_experiments={"trace_lifecycle": "stream"},
685+
)
686+
687+
sentry_sdk.traces.new_trace()
688+
689+
with sentry_sdk.traces.start_span(name="span") as span:
690+
assert span.sampled is True
691+
692+
trace_id = span.trace_id
693+
span_id = span.span_id
694+
695+
traceparent = sentry_sdk.get_traceparent()
696+
assert traceparent == f"{trace_id}-{span_id}-1"
697+
698+
baggage = sentry_sdk.get_baggage()
699+
baggage_items = dict(tuple(item.split("=")) for item in baggage.split(","))
700+
assert "sentry-trace_id" in baggage_items
701+
assert baggage_items["sentry-trace_id"] == trace_id
702+
assert "sentry-sampled" in baggage_items
703+
assert baggage_items["sentry-sampled"] == "true"
704+
705+
681706
def test_trace_decorator(sentry_init, capture_envelopes):
682707
sentry_init(
683708
traces_sample_rate=1.0,

0 commit comments

Comments
 (0)