sentry-sdk 3.0.0a1__py2.py3-none-any.whl → 3.0.0a3__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of sentry-sdk might be problematic. Click here for more details.

Files changed (157) hide show
  1. sentry_sdk/__init__.py +2 -0
  2. sentry_sdk/_compat.py +5 -12
  3. sentry_sdk/_init_implementation.py +7 -7
  4. sentry_sdk/_log_batcher.py +17 -29
  5. sentry_sdk/_lru_cache.py +7 -9
  6. sentry_sdk/_queue.py +2 -4
  7. sentry_sdk/_types.py +11 -18
  8. sentry_sdk/_werkzeug.py +5 -7
  9. sentry_sdk/ai/monitoring.py +44 -31
  10. sentry_sdk/ai/utils.py +3 -4
  11. sentry_sdk/api.py +75 -87
  12. sentry_sdk/attachments.py +10 -12
  13. sentry_sdk/client.py +137 -155
  14. sentry_sdk/consts.py +430 -174
  15. sentry_sdk/crons/api.py +16 -17
  16. sentry_sdk/crons/decorator.py +25 -27
  17. sentry_sdk/debug.py +4 -6
  18. sentry_sdk/envelope.py +46 -112
  19. sentry_sdk/feature_flags.py +9 -15
  20. sentry_sdk/integrations/__init__.py +24 -19
  21. sentry_sdk/integrations/_asgi_common.py +15 -18
  22. sentry_sdk/integrations/_wsgi_common.py +22 -33
  23. sentry_sdk/integrations/aiohttp.py +32 -30
  24. sentry_sdk/integrations/anthropic.py +42 -37
  25. sentry_sdk/integrations/argv.py +3 -4
  26. sentry_sdk/integrations/ariadne.py +16 -18
  27. sentry_sdk/integrations/arq.py +21 -29
  28. sentry_sdk/integrations/asgi.py +63 -37
  29. sentry_sdk/integrations/asyncio.py +14 -16
  30. sentry_sdk/integrations/atexit.py +6 -10
  31. sentry_sdk/integrations/aws_lambda.py +26 -36
  32. sentry_sdk/integrations/beam.py +10 -18
  33. sentry_sdk/integrations/boto3.py +18 -16
  34. sentry_sdk/integrations/bottle.py +25 -34
  35. sentry_sdk/integrations/celery/__init__.py +41 -61
  36. sentry_sdk/integrations/celery/beat.py +23 -27
  37. sentry_sdk/integrations/celery/utils.py +15 -17
  38. sentry_sdk/integrations/chalice.py +8 -10
  39. sentry_sdk/integrations/clickhouse_driver.py +21 -31
  40. sentry_sdk/integrations/cloud_resource_context.py +9 -16
  41. sentry_sdk/integrations/cohere.py +27 -33
  42. sentry_sdk/integrations/dedupe.py +5 -8
  43. sentry_sdk/integrations/django/__init__.py +57 -72
  44. sentry_sdk/integrations/django/asgi.py +26 -34
  45. sentry_sdk/integrations/django/caching.py +23 -19
  46. sentry_sdk/integrations/django/middleware.py +17 -20
  47. sentry_sdk/integrations/django/signals_handlers.py +11 -10
  48. sentry_sdk/integrations/django/templates.py +19 -16
  49. sentry_sdk/integrations/django/transactions.py +16 -11
  50. sentry_sdk/integrations/django/views.py +6 -10
  51. sentry_sdk/integrations/dramatiq.py +21 -21
  52. sentry_sdk/integrations/excepthook.py +10 -10
  53. sentry_sdk/integrations/executing.py +3 -4
  54. sentry_sdk/integrations/falcon.py +27 -42
  55. sentry_sdk/integrations/fastapi.py +13 -16
  56. sentry_sdk/integrations/flask.py +31 -38
  57. sentry_sdk/integrations/gcp.py +13 -16
  58. sentry_sdk/integrations/gnu_backtrace.py +4 -6
  59. sentry_sdk/integrations/gql.py +16 -17
  60. sentry_sdk/integrations/graphene.py +13 -12
  61. sentry_sdk/integrations/grpc/__init__.py +19 -1
  62. sentry_sdk/integrations/grpc/aio/server.py +15 -14
  63. sentry_sdk/integrations/grpc/client.py +19 -9
  64. sentry_sdk/integrations/grpc/consts.py +2 -0
  65. sentry_sdk/integrations/grpc/server.py +12 -8
  66. sentry_sdk/integrations/httpx.py +9 -12
  67. sentry_sdk/integrations/huey.py +13 -20
  68. sentry_sdk/integrations/huggingface_hub.py +18 -18
  69. sentry_sdk/integrations/langchain.py +203 -113
  70. sentry_sdk/integrations/launchdarkly.py +13 -10
  71. sentry_sdk/integrations/litestar.py +37 -35
  72. sentry_sdk/integrations/logging.py +52 -65
  73. sentry_sdk/integrations/loguru.py +127 -57
  74. sentry_sdk/integrations/modules.py +3 -4
  75. sentry_sdk/integrations/openai.py +100 -88
  76. sentry_sdk/integrations/openai_agents/__init__.py +49 -0
  77. sentry_sdk/integrations/openai_agents/consts.py +1 -0
  78. sentry_sdk/integrations/openai_agents/patches/__init__.py +4 -0
  79. sentry_sdk/integrations/openai_agents/patches/agent_run.py +152 -0
  80. sentry_sdk/integrations/openai_agents/patches/models.py +52 -0
  81. sentry_sdk/integrations/openai_agents/patches/runner.py +42 -0
  82. sentry_sdk/integrations/openai_agents/patches/tools.py +84 -0
  83. sentry_sdk/integrations/openai_agents/spans/__init__.py +5 -0
  84. sentry_sdk/integrations/openai_agents/spans/agent_workflow.py +20 -0
  85. sentry_sdk/integrations/openai_agents/spans/ai_client.py +46 -0
  86. sentry_sdk/integrations/openai_agents/spans/execute_tool.py +47 -0
  87. sentry_sdk/integrations/openai_agents/spans/handoff.py +24 -0
  88. sentry_sdk/integrations/openai_agents/spans/invoke_agent.py +41 -0
  89. sentry_sdk/integrations/openai_agents/utils.py +201 -0
  90. sentry_sdk/integrations/openfeature.py +11 -6
  91. sentry_sdk/integrations/pure_eval.py +6 -10
  92. sentry_sdk/integrations/pymongo.py +13 -17
  93. sentry_sdk/integrations/pyramid.py +31 -36
  94. sentry_sdk/integrations/quart.py +23 -28
  95. sentry_sdk/integrations/ray.py +73 -64
  96. sentry_sdk/integrations/redis/__init__.py +7 -4
  97. sentry_sdk/integrations/redis/_async_common.py +25 -12
  98. sentry_sdk/integrations/redis/_sync_common.py +19 -13
  99. sentry_sdk/integrations/redis/modules/caches.py +17 -8
  100. sentry_sdk/integrations/redis/modules/queries.py +9 -8
  101. sentry_sdk/integrations/redis/rb.py +3 -2
  102. sentry_sdk/integrations/redis/redis.py +4 -4
  103. sentry_sdk/integrations/redis/redis_cluster.py +21 -13
  104. sentry_sdk/integrations/redis/redis_py_cluster_legacy.py +3 -2
  105. sentry_sdk/integrations/redis/utils.py +23 -24
  106. sentry_sdk/integrations/rq.py +13 -16
  107. sentry_sdk/integrations/rust_tracing.py +9 -6
  108. sentry_sdk/integrations/sanic.py +34 -46
  109. sentry_sdk/integrations/serverless.py +22 -27
  110. sentry_sdk/integrations/socket.py +27 -15
  111. sentry_sdk/integrations/spark/__init__.py +1 -0
  112. sentry_sdk/integrations/spark/spark_driver.py +45 -83
  113. sentry_sdk/integrations/spark/spark_worker.py +7 -11
  114. sentry_sdk/integrations/sqlalchemy.py +22 -19
  115. sentry_sdk/integrations/starlette.py +86 -90
  116. sentry_sdk/integrations/starlite.py +28 -34
  117. sentry_sdk/integrations/statsig.py +5 -4
  118. sentry_sdk/integrations/stdlib.py +28 -24
  119. sentry_sdk/integrations/strawberry.py +62 -49
  120. sentry_sdk/integrations/sys_exit.py +7 -11
  121. sentry_sdk/integrations/threading.py +12 -14
  122. sentry_sdk/integrations/tornado.py +28 -32
  123. sentry_sdk/integrations/trytond.py +4 -3
  124. sentry_sdk/integrations/typer.py +8 -6
  125. sentry_sdk/integrations/unleash.py +5 -4
  126. sentry_sdk/integrations/wsgi.py +47 -46
  127. sentry_sdk/logger.py +41 -10
  128. sentry_sdk/monitor.py +16 -28
  129. sentry_sdk/opentelemetry/consts.py +11 -4
  130. sentry_sdk/opentelemetry/contextvars_context.py +26 -16
  131. sentry_sdk/opentelemetry/propagator.py +38 -21
  132. sentry_sdk/opentelemetry/sampler.py +51 -34
  133. sentry_sdk/opentelemetry/scope.py +36 -37
  134. sentry_sdk/opentelemetry/span_processor.py +48 -58
  135. sentry_sdk/opentelemetry/tracing.py +58 -14
  136. sentry_sdk/opentelemetry/utils.py +186 -194
  137. sentry_sdk/profiler/continuous_profiler.py +108 -97
  138. sentry_sdk/profiler/transaction_profiler.py +70 -97
  139. sentry_sdk/profiler/utils.py +11 -15
  140. sentry_sdk/scope.py +251 -273
  141. sentry_sdk/scrubber.py +22 -26
  142. sentry_sdk/serializer.py +40 -54
  143. sentry_sdk/session.py +44 -61
  144. sentry_sdk/sessions.py +35 -49
  145. sentry_sdk/spotlight.py +15 -21
  146. sentry_sdk/tracing.py +121 -187
  147. sentry_sdk/tracing_utils.py +104 -122
  148. sentry_sdk/transport.py +131 -157
  149. sentry_sdk/utils.py +232 -309
  150. sentry_sdk/worker.py +16 -28
  151. {sentry_sdk-3.0.0a1.dist-info → sentry_sdk-3.0.0a3.dist-info}/METADATA +3 -3
  152. sentry_sdk-3.0.0a3.dist-info/RECORD +168 -0
  153. {sentry_sdk-3.0.0a1.dist-info → sentry_sdk-3.0.0a3.dist-info}/WHEEL +1 -1
  154. sentry_sdk-3.0.0a1.dist-info/RECORD +0 -154
  155. {sentry_sdk-3.0.0a1.dist-info → sentry_sdk-3.0.0a3.dist-info}/entry_points.txt +0 -0
  156. {sentry_sdk-3.0.0a1.dist-info → sentry_sdk-3.0.0a3.dist-info}/licenses/LICENSE +0 -0
  157. {sentry_sdk-3.0.0a1.dist-info → sentry_sdk-3.0.0a3.dist-info}/top_level.txt +0 -0
@@ -1,3 +1,4 @@
1
+ from __future__ import annotations
1
2
  import sentry_sdk
2
3
  from sentry_sdk.consts import SOURCE_FOR_STYLE
3
4
  from sentry_sdk.integrations import _check_minimum_version, DidNotEnable, Integration
@@ -57,10 +58,9 @@ class FlaskIntegration(Integration):
57
58
 
58
59
  def __init__(
59
60
  self,
60
- transaction_style="endpoint", # type: str
61
- http_methods_to_capture=DEFAULT_HTTP_METHODS_TO_CAPTURE, # type: tuple[str, ...]
62
- ):
63
- # type: (...) -> None
61
+ transaction_style: str = "endpoint",
62
+ http_methods_to_capture: tuple[str, ...] = DEFAULT_HTTP_METHODS_TO_CAPTURE,
63
+ ) -> None:
64
64
  if transaction_style not in TRANSACTION_STYLE_VALUES:
65
65
  raise ValueError(
66
66
  "Invalid value for transaction_style: %s (must be in %s)"
@@ -70,8 +70,7 @@ class FlaskIntegration(Integration):
70
70
  self.http_methods_to_capture = tuple(map(str.upper, http_methods_to_capture))
71
71
 
72
72
  @staticmethod
73
- def setup_once():
74
- # type: () -> None
73
+ def setup_once() -> None:
75
74
  try:
76
75
  from quart import Quart # type: ignore
77
76
 
@@ -93,8 +92,9 @@ class FlaskIntegration(Integration):
93
92
 
94
93
  old_app = Flask.__call__
95
94
 
96
- def sentry_patched_wsgi_app(self, environ, start_response):
97
- # type: (Any, Dict[str, str], Callable[..., Any]) -> _ScopedResponse
95
+ def sentry_patched_wsgi_app(
96
+ self: Any, environ: Dict[str, str], start_response: Callable[..., Any]
97
+ ) -> _ScopedResponse:
98
98
  if sentry_sdk.get_client().get_integration(FlaskIntegration) is None:
99
99
  return old_app(self, environ, start_response)
100
100
 
@@ -114,8 +114,9 @@ class FlaskIntegration(Integration):
114
114
  Flask.__call__ = sentry_patched_wsgi_app
115
115
 
116
116
 
117
- def _add_sentry_trace(sender, template, context, **extra):
118
- # type: (Flask, Any, Dict[str, Any], **Any) -> None
117
+ def _add_sentry_trace(
118
+ sender: Flask, template: Any, context: Dict[str, Any], **extra: Any
119
+ ) -> None:
119
120
  if "sentry_trace" in context:
120
121
  return
121
122
 
@@ -125,8 +126,9 @@ def _add_sentry_trace(sender, template, context, **extra):
125
126
  context["sentry_trace_meta"] = trace_meta
126
127
 
127
128
 
128
- def _set_transaction_name_and_source(scope, transaction_style, request):
129
- # type: (sentry_sdk.Scope, str, Request) -> None
129
+ def _set_transaction_name_and_source(
130
+ scope: sentry_sdk.Scope, transaction_style: str, request: Request
131
+ ) -> None:
130
132
  try:
131
133
  name_for_style = {
132
134
  "url": request.url_rule.rule,
@@ -140,8 +142,7 @@ def _set_transaction_name_and_source(scope, transaction_style, request):
140
142
  pass
141
143
 
142
144
 
143
- def _request_started(app, **kwargs):
144
- # type: (Flask, **Any) -> None
145
+ def _request_started(app: Flask, **kwargs: Any) -> None:
145
146
  integration = sentry_sdk.get_client().get_integration(FlaskIntegration)
146
147
  if integration is None:
147
148
  return
@@ -160,47 +161,39 @@ def _request_started(app, **kwargs):
160
161
 
161
162
 
162
163
  class FlaskRequestExtractor(RequestExtractor):
163
- def env(self):
164
- # type: () -> Dict[str, str]
164
+ def env(self) -> Dict[str, str]:
165
165
  return self.request.environ
166
166
 
167
- def cookies(self):
168
- # type: () -> Dict[Any, Any]
167
+ def cookies(self) -> Dict[Any, Any]:
169
168
  return {
170
169
  k: v[0] if isinstance(v, list) and len(v) == 1 else v
171
170
  for k, v in self.request.cookies.items()
172
171
  }
173
172
 
174
- def raw_data(self):
175
- # type: () -> bytes
173
+ def raw_data(self) -> bytes:
176
174
  return self.request.get_data()
177
175
 
178
- def form(self):
179
- # type: () -> ImmutableMultiDict[str, Any]
176
+ def form(self) -> ImmutableMultiDict[str, Any]:
180
177
  return self.request.form
181
178
 
182
- def files(self):
183
- # type: () -> ImmutableMultiDict[str, Any]
179
+ def files(self) -> ImmutableMultiDict[str, Any]:
184
180
  return self.request.files
185
181
 
186
- def is_json(self):
187
- # type: () -> bool
182
+ def is_json(self) -> bool:
188
183
  return self.request.is_json
189
184
 
190
- def json(self):
191
- # type: () -> Any
185
+ def json(self) -> Any:
192
186
  return self.request.get_json(silent=True)
193
187
 
194
- def size_of_file(self, file):
195
- # type: (FileStorage) -> int
188
+ def size_of_file(self, file: FileStorage) -> int:
196
189
  return file.content_length
197
190
 
198
191
 
199
- def _make_request_event_processor(app, request, integration):
200
- # type: (Flask, Callable[[], Request], FlaskIntegration) -> EventProcessor
192
+ def _make_request_event_processor(
193
+ app: Flask, request: Callable[[], Request], integration: FlaskIntegration
194
+ ) -> EventProcessor:
201
195
 
202
- def inner(event, hint):
203
- # type: (Event, dict[str, Any]) -> Event
196
+ def inner(event: Event, hint: dict[str, Any]) -> Event:
204
197
 
205
198
  # if the request is gone we are fine not logging the data from
206
199
  # it. This might happen if the processor is pushed away to
@@ -221,8 +214,9 @@ def _make_request_event_processor(app, request, integration):
221
214
 
222
215
 
223
216
  @ensure_integration_enabled(FlaskIntegration)
224
- def _capture_exception(sender, exception, **kwargs):
225
- # type: (Flask, Union[ValueError, BaseException], **Any) -> None
217
+ def _capture_exception(
218
+ sender: Flask, exception: Union[ValueError, BaseException], **kwargs: Any
219
+ ) -> None:
226
220
  event, hint = event_from_exception(
227
221
  exception,
228
222
  client_options=sentry_sdk.get_client().options,
@@ -232,8 +226,7 @@ def _capture_exception(sender, exception, **kwargs):
232
226
  sentry_sdk.capture_event(event, hint=hint)
233
227
 
234
228
 
235
- def _add_user_to_event(event):
236
- # type: (Event) -> None
229
+ def _add_user_to_event(event: Event) -> None:
237
230
  if flask_login is None:
238
231
  return
239
232
 
@@ -1,3 +1,4 @@
1
+ from __future__ import annotations
1
2
  import functools
2
3
  import sys
3
4
  from copy import deepcopy
@@ -39,11 +40,11 @@ if TYPE_CHECKING:
39
40
  F = TypeVar("F", bound=Callable[..., Any])
40
41
 
41
42
 
42
- def _wrap_func(func):
43
- # type: (F) -> F
43
+ def _wrap_func(func: F) -> F:
44
44
  @functools.wraps(func)
45
- def sentry_func(functionhandler, gcp_event, *args, **kwargs):
46
- # type: (Any, Any, *Any, **Any) -> Any
45
+ def sentry_func(
46
+ functionhandler: Any, gcp_event: Any, *args: Any, **kwargs: Any
47
+ ) -> Any:
47
48
  client = sentry_sdk.get_client()
48
49
 
49
50
  integration = client.get_integration(GcpIntegration)
@@ -118,13 +119,11 @@ class GcpIntegration(Integration):
118
119
  identifier = "gcp"
119
120
  origin = f"auto.function.{identifier}"
120
121
 
121
- def __init__(self, timeout_warning=False):
122
- # type: (bool) -> None
122
+ def __init__(self, timeout_warning: bool = False) -> None:
123
123
  self.timeout_warning = timeout_warning
124
124
 
125
125
  @staticmethod
126
- def setup_once():
127
- # type: () -> None
126
+ def setup_once() -> None:
128
127
  import __main__ as gcp_functions
129
128
 
130
129
  if not hasattr(gcp_functions, "worker_v1"):
@@ -140,11 +139,11 @@ class GcpIntegration(Integration):
140
139
  )
141
140
 
142
141
 
143
- def _make_request_event_processor(gcp_event, configured_timeout, initial_time):
144
- # type: (Any, Any, Any) -> EventProcessor
142
+ def _make_request_event_processor(
143
+ gcp_event: Any, configured_timeout: Any, initial_time: Any
144
+ ) -> EventProcessor:
145
145
 
146
- def event_processor(event, hint):
147
- # type: (Event, Hint) -> Optional[Event]
146
+ def event_processor(event: Event, hint: Hint) -> Optional[Event]:
148
147
 
149
148
  final_time = datetime.now(timezone.utc)
150
149
  time_diff = final_time - initial_time
@@ -195,8 +194,7 @@ def _make_request_event_processor(gcp_event, configured_timeout, initial_time):
195
194
  return event_processor
196
195
 
197
196
 
198
- def _get_google_cloud_logs_url(final_time):
199
- # type: (datetime) -> str
197
+ def _get_google_cloud_logs_url(final_time: datetime) -> str:
200
198
  """
201
199
  Generates a Google Cloud Logs console URL based on the environment variables
202
200
  Arguments:
@@ -238,8 +236,7 @@ EVENT_TO_ATTRIBUTE = {
238
236
  }
239
237
 
240
238
 
241
- def _prepopulate_attributes(gcp_event):
242
- # type: (Any) -> dict[str, Any]
239
+ def _prepopulate_attributes(gcp_event: Any) -> dict[str, Any]:
243
240
  attributes = {
244
241
  "cloud.provider": "gcp",
245
242
  }
@@ -1,3 +1,4 @@
1
+ from __future__ import annotations
1
2
  import re
2
3
 
3
4
  import sentry_sdk
@@ -38,17 +39,14 @@ class GnuBacktraceIntegration(Integration):
38
39
  identifier = "gnu_backtrace"
39
40
 
40
41
  @staticmethod
41
- def setup_once():
42
- # type: () -> None
42
+ def setup_once() -> None:
43
43
  @add_global_event_processor
44
- def process_gnu_backtrace(event, hint):
45
- # type: (Event, dict[str, Any]) -> Event
44
+ def process_gnu_backtrace(event: Event, hint: dict[str, Any]) -> Event:
46
45
  with capture_internal_exceptions():
47
46
  return _process_gnu_backtrace(event, hint)
48
47
 
49
48
 
50
- def _process_gnu_backtrace(event, hint):
51
- # type: (Event, dict[str, Any]) -> Event
49
+ def _process_gnu_backtrace(event: Event, hint: dict[str, Any]) -> Event:
52
50
  if sentry_sdk.get_client().get_integration(GnuBacktraceIntegration) is None:
53
51
  return event
54
52
 
@@ -1,3 +1,4 @@
1
+ from __future__ import annotations
1
2
  import sentry_sdk
2
3
  from sentry_sdk.utils import (
3
4
  event_from_exception,
@@ -34,19 +35,17 @@ class GQLIntegration(Integration):
34
35
  identifier = "gql"
35
36
 
36
37
  @staticmethod
37
- def setup_once():
38
- # type: () -> None
38
+ def setup_once() -> None:
39
39
  gql_version = parse_version(gql.__version__)
40
40
  _check_minimum_version(GQLIntegration, gql_version)
41
41
 
42
42
  _patch_execute()
43
43
 
44
44
 
45
- def _data_from_document(document):
46
- # type: (DocumentNode) -> EventDataType
45
+ def _data_from_document(document: DocumentNode) -> EventDataType:
47
46
  try:
48
47
  operation_ast = get_operation_ast(document)
49
- data = {"query": print_ast(document)} # type: EventDataType
48
+ data: EventDataType = {"query": print_ast(document)}
50
49
 
51
50
  if operation_ast is not None:
52
51
  data["variables"] = operation_ast.variable_definitions
@@ -58,8 +57,7 @@ def _data_from_document(document):
58
57
  return dict()
59
58
 
60
59
 
61
- def _transport_method(transport):
62
- # type: (Union[Transport, AsyncTransport]) -> str
60
+ def _transport_method(transport: Union[Transport, AsyncTransport]) -> str:
63
61
  """
64
62
  The RequestsHTTPTransport allows defining the HTTP method; all
65
63
  other transports use POST.
@@ -70,8 +68,9 @@ def _transport_method(transport):
70
68
  return "POST"
71
69
 
72
70
 
73
- def _request_info_from_transport(transport):
74
- # type: (Union[Transport, AsyncTransport, None]) -> Dict[str, str]
71
+ def _request_info_from_transport(
72
+ transport: Union[Transport, AsyncTransport, None],
73
+ ) -> Dict[str, str]:
75
74
  if transport is None:
76
75
  return {}
77
76
 
@@ -87,13 +86,13 @@ def _request_info_from_transport(transport):
87
86
  return request_info
88
87
 
89
88
 
90
- def _patch_execute():
91
- # type: () -> None
89
+ def _patch_execute() -> None:
92
90
  real_execute = gql.Client.execute
93
91
 
94
92
  @ensure_integration_enabled(GQLIntegration, real_execute)
95
- def sentry_patched_execute(self, document, *args, **kwargs):
96
- # type: (gql.Client, DocumentNode, Any, Any) -> Any
93
+ def sentry_patched_execute(
94
+ self: gql.Client, document: DocumentNode, *args: Any, **kwargs: Any
95
+ ) -> Any:
97
96
  scope = sentry_sdk.get_isolation_scope()
98
97
  scope.add_event_processor(_make_gql_event_processor(self, document))
99
98
 
@@ -112,10 +111,10 @@ def _patch_execute():
112
111
  gql.Client.execute = sentry_patched_execute
113
112
 
114
113
 
115
- def _make_gql_event_processor(client, document):
116
- # type: (gql.Client, DocumentNode) -> EventProcessor
117
- def processor(event, hint):
118
- # type: (Event, dict[str, Any]) -> Event
114
+ def _make_gql_event_processor(
115
+ client: gql.Client, document: DocumentNode
116
+ ) -> EventProcessor:
117
+ def processor(event: Event, hint: dict[str, Any]) -> Event:
119
118
  try:
120
119
  errors = hint["exc_info"][1].errors
121
120
  except (AttributeError, KeyError):
@@ -1,3 +1,4 @@
1
+ from __future__ import annotations
1
2
  from contextlib import contextmanager
2
3
 
3
4
  import sentry_sdk
@@ -31,22 +32,21 @@ class GrapheneIntegration(Integration):
31
32
  identifier = "graphene"
32
33
 
33
34
  @staticmethod
34
- def setup_once():
35
- # type: () -> None
35
+ def setup_once() -> None:
36
36
  version = package_version("graphene")
37
37
  _check_minimum_version(GrapheneIntegration, version)
38
38
 
39
39
  _patch_graphql()
40
40
 
41
41
 
42
- def _patch_graphql():
43
- # type: () -> None
42
+ def _patch_graphql() -> None:
44
43
  old_graphql_sync = graphene_schema.graphql_sync
45
44
  old_graphql_async = graphene_schema.graphql
46
45
 
47
46
  @ensure_integration_enabled(GrapheneIntegration, old_graphql_sync)
48
- def _sentry_patched_graphql_sync(schema, source, *args, **kwargs):
49
- # type: (GraphQLSchema, Union[str, Source], Any, Any) -> ExecutionResult
47
+ def _sentry_patched_graphql_sync(
48
+ schema: GraphQLSchema, source: Union[str, Source], *args: Any, **kwargs: Any
49
+ ) -> ExecutionResult:
50
50
  scope = sentry_sdk.get_isolation_scope()
51
51
  scope.add_event_processor(_event_processor)
52
52
 
@@ -68,8 +68,9 @@ def _patch_graphql():
68
68
 
69
69
  return result
70
70
 
71
- async def _sentry_patched_graphql_async(schema, source, *args, **kwargs):
72
- # type: (GraphQLSchema, Union[str, Source], Any, Any) -> ExecutionResult
71
+ async def _sentry_patched_graphql_async(
72
+ schema: GraphQLSchema, source: Union[str, Source], *args: Any, **kwargs: Any
73
+ ) -> ExecutionResult:
73
74
  integration = sentry_sdk.get_client().get_integration(GrapheneIntegration)
74
75
  if integration is None:
75
76
  return await old_graphql_async(schema, source, *args, **kwargs)
@@ -99,8 +100,7 @@ def _patch_graphql():
99
100
  graphene_schema.graphql = _sentry_patched_graphql_async
100
101
 
101
102
 
102
- def _event_processor(event, hint):
103
- # type: (Event, Dict[str, Any]) -> Event
103
+ def _event_processor(event: Event, hint: Dict[str, Any]) -> Event:
104
104
  if should_send_default_pii():
105
105
  request_info = event.setdefault("request", {})
106
106
  request_info["api_target"] = "graphql"
@@ -112,8 +112,9 @@ def _event_processor(event, hint):
112
112
 
113
113
 
114
114
  @contextmanager
115
- def graphql_span(schema, source, kwargs):
116
- # type: (GraphQLSchema, Union[str, Source], Dict[str, Any]) -> Generator[None, None, None]
115
+ def graphql_span(
116
+ schema: GraphQLSchema, source: Union[str, Source], kwargs: Dict[str, Any]
117
+ ) -> Generator[None, None, None]:
117
118
  operation_name = kwargs.get("operation_name")
118
119
 
119
120
  operation_type = "query"
@@ -1,3 +1,4 @@
1
+ from __future__ import annotations
1
2
  from functools import wraps
2
3
 
3
4
  import grpc
@@ -6,6 +7,7 @@ from grpc.aio import Channel as AsyncChannel
6
7
  from grpc.aio import Server as AsyncServer
7
8
 
8
9
  from sentry_sdk.integrations import Integration
10
+ from sentry_sdk.utils import parse_version
9
11
 
10
12
  from .client import ClientInterceptor
11
13
  from .server import ServerInterceptor
@@ -41,6 +43,8 @@ else:
41
43
 
42
44
  P = ParamSpec("P")
43
45
 
46
+ GRPC_VERSION = parse_version(grpc.__version__)
47
+
44
48
 
45
49
  def _wrap_channel_sync(func: Callable[P, Channel]) -> Callable[P, Channel]:
46
50
  "Wrapper for synchronous secure and insecure channel."
@@ -127,7 +131,21 @@ def _wrap_async_server(func: Callable[P, AsyncServer]) -> Callable[P, AsyncServe
127
131
  **kwargs: P.kwargs,
128
132
  ) -> Server:
129
133
  server_interceptor = AsyncServerInterceptor()
130
- interceptors = (server_interceptor, *(interceptors or []))
134
+ interceptors: Sequence[grpc.ServerInterceptor] = [
135
+ server_interceptor,
136
+ *(interceptors or []),
137
+ ]
138
+
139
+ try:
140
+ # We prefer interceptors as a list because of compatibility with
141
+ # opentelemetry https://github.com/getsentry/sentry-python/issues/4389
142
+ # However, prior to grpc 1.42.0, only tuples were accepted, so we
143
+ # have no choice there.
144
+ if GRPC_VERSION is not None and GRPC_VERSION < (1, 42, 0):
145
+ interceptors = tuple(interceptors)
146
+ except Exception:
147
+ pass
148
+
131
149
  return func(*args, interceptors=interceptors, **kwargs) # type: ignore
132
150
 
133
151
  return patched_aio_server # type: ignore
@@ -1,3 +1,4 @@
1
+ from __future__ import annotations
1
2
  import sentry_sdk
2
3
  from sentry_sdk.consts import OP
3
4
  from sentry_sdk.integrations import DidNotEnable
@@ -21,14 +22,19 @@ except ImportError:
21
22
 
22
23
 
23
24
  class ServerInterceptor(grpc.aio.ServerInterceptor): # type: ignore
24
- def __init__(self, find_name=None):
25
- # type: (ServerInterceptor, Callable[[ServicerContext], str] | None) -> None
25
+ def __init__(
26
+ self: ServerInterceptor,
27
+ find_name: Callable[[ServicerContext], str] | None = None,
28
+ ) -> None:
26
29
  self._find_method_name = find_name or self._find_name
27
30
 
28
31
  super().__init__()
29
32
 
30
- async def intercept_service(self, continuation, handler_call_details):
31
- # type: (ServerInterceptor, Callable[[HandlerCallDetails], Awaitable[RpcMethodHandler]], HandlerCallDetails) -> Optional[Awaitable[RpcMethodHandler]]
33
+ async def intercept_service(
34
+ self: ServerInterceptor,
35
+ continuation: Callable[[HandlerCallDetails], Awaitable[RpcMethodHandler]],
36
+ handler_call_details: HandlerCallDetails,
37
+ ) -> Optional[Awaitable[RpcMethodHandler]]:
32
38
  self._handler_call_details = handler_call_details
33
39
  handler = await continuation(handler_call_details)
34
40
  if handler is None:
@@ -37,8 +43,7 @@ class ServerInterceptor(grpc.aio.ServerInterceptor): # type: ignore
37
43
  if not handler.request_streaming and not handler.response_streaming:
38
44
  handler_factory = grpc.unary_unary_rpc_method_handler
39
45
 
40
- async def wrapped(request, context):
41
- # type: (Any, ServicerContext) -> Any
46
+ async def wrapped(request: Any, context: ServicerContext) -> Any:
42
47
  name = self._find_method_name(context)
43
48
  if not name:
44
49
  return await handler(request, context)
@@ -66,24 +71,21 @@ class ServerInterceptor(grpc.aio.ServerInterceptor): # type: ignore
66
71
  elif not handler.request_streaming and handler.response_streaming:
67
72
  handler_factory = grpc.unary_stream_rpc_method_handler
68
73
 
69
- async def wrapped(request, context): # type: ignore
70
- # type: (Any, ServicerContext) -> Any
74
+ async def wrapped(request: Any, context: ServicerContext) -> Any: # type: ignore
71
75
  async for r in handler.unary_stream(request, context):
72
76
  yield r
73
77
 
74
78
  elif handler.request_streaming and not handler.response_streaming:
75
79
  handler_factory = grpc.stream_unary_rpc_method_handler
76
80
 
77
- async def wrapped(request, context):
78
- # type: (Any, ServicerContext) -> Any
81
+ async def wrapped(request: Any, context: ServicerContext) -> Any:
79
82
  response = handler.stream_unary(request, context)
80
83
  return await response
81
84
 
82
85
  elif handler.request_streaming and handler.response_streaming:
83
86
  handler_factory = grpc.stream_stream_rpc_method_handler
84
87
 
85
- async def wrapped(request, context): # type: ignore
86
- # type: (Any, ServicerContext) -> Any
88
+ async def wrapped(request: Any, context: ServicerContext) -> Any: # type: ignore
87
89
  async for r in handler.stream_stream(request, context):
88
90
  yield r
89
91
 
@@ -93,6 +95,5 @@ class ServerInterceptor(grpc.aio.ServerInterceptor): # type: ignore
93
95
  response_serializer=handler.response_serializer,
94
96
  )
95
97
 
96
- def _find_name(self, context):
97
- # type: (ServicerContext) -> str
98
+ def _find_name(self, context: ServicerContext) -> str:
98
99
  return self._handler_call_details.method
@@ -1,3 +1,4 @@
1
+ from __future__ import annotations
1
2
  import sentry_sdk
2
3
  from sentry_sdk.consts import OP
3
4
  from sentry_sdk.integrations import DidNotEnable
@@ -23,8 +24,12 @@ class ClientInterceptor(
23
24
  ):
24
25
  _is_intercepted = False
25
26
 
26
- def intercept_unary_unary(self, continuation, client_call_details, request):
27
- # type: (ClientInterceptor, Callable[[ClientCallDetails, Message], _UnaryOutcome], ClientCallDetails, Message) -> _UnaryOutcome
27
+ def intercept_unary_unary(
28
+ self: ClientInterceptor,
29
+ continuation: Callable[[ClientCallDetails, Message], _UnaryOutcome],
30
+ client_call_details: ClientCallDetails,
31
+ request: Message,
32
+ ) -> _UnaryOutcome:
28
33
  method = client_call_details.method
29
34
 
30
35
  with sentry_sdk.start_span(
@@ -45,8 +50,14 @@ class ClientInterceptor(
45
50
 
46
51
  return response
47
52
 
48
- def intercept_unary_stream(self, continuation, client_call_details, request):
49
- # type: (ClientInterceptor, Callable[[ClientCallDetails, Message], Union[Iterable[Any], UnaryStreamCall]], ClientCallDetails, Message) -> Union[Iterator[Message], Call]
53
+ def intercept_unary_stream(
54
+ self: ClientInterceptor,
55
+ continuation: Callable[
56
+ [ClientCallDetails, Message], Union[Iterable[Any], UnaryStreamCall]
57
+ ],
58
+ client_call_details: ClientCallDetails,
59
+ request: Message,
60
+ ) -> Union[Iterator[Message], Call]:
50
61
  method = client_call_details.method
51
62
 
52
63
  with sentry_sdk.start_span(
@@ -62,17 +73,16 @@ class ClientInterceptor(
62
73
  client_call_details
63
74
  )
64
75
 
65
- response = continuation(
66
- client_call_details, request
67
- ) # type: UnaryStreamCall
76
+ response: UnaryStreamCall = continuation(client_call_details, request)
68
77
  # Setting code on unary-stream leads to execution getting stuck
69
78
  # span.set_attribute("code", response.code().name)
70
79
 
71
80
  return response
72
81
 
73
82
  @staticmethod
74
- def _update_client_call_details_metadata_from_scope(client_call_details):
75
- # type: (ClientCallDetails) -> ClientCallDetails
83
+ def _update_client_call_details_metadata_from_scope(
84
+ client_call_details: ClientCallDetails,
85
+ ) -> ClientCallDetails:
76
86
  metadata = (
77
87
  list(client_call_details.metadata) if client_call_details.metadata else []
78
88
  )
@@ -1 +1,3 @@
1
+ from __future__ import annotations
2
+
1
3
  SPAN_ORIGIN = "auto.grpc.grpc"
@@ -1,3 +1,4 @@
1
+ from __future__ import annotations
1
2
  import sentry_sdk
2
3
  from sentry_sdk.consts import OP
3
4
  from sentry_sdk.integrations import DidNotEnable
@@ -18,20 +19,24 @@ except ImportError:
18
19
 
19
20
 
20
21
  class ServerInterceptor(grpc.ServerInterceptor): # type: ignore
21
- def __init__(self, find_name=None):
22
- # type: (ServerInterceptor, Optional[Callable[[ServicerContext], str]]) -> None
22
+ def __init__(
23
+ self: ServerInterceptor,
24
+ find_name: Optional[Callable[[ServicerContext], str]] = None,
25
+ ) -> None:
23
26
  self._find_method_name = find_name or ServerInterceptor._find_name
24
27
 
25
28
  super().__init__()
26
29
 
27
- def intercept_service(self, continuation, handler_call_details):
28
- # type: (ServerInterceptor, Callable[[HandlerCallDetails], RpcMethodHandler], HandlerCallDetails) -> RpcMethodHandler
30
+ def intercept_service(
31
+ self: ServerInterceptor,
32
+ continuation: Callable[[HandlerCallDetails], RpcMethodHandler],
33
+ handler_call_details: HandlerCallDetails,
34
+ ) -> RpcMethodHandler:
29
35
  handler = continuation(handler_call_details)
30
36
  if not handler or not handler.unary_unary:
31
37
  return handler
32
38
 
33
- def behavior(request, context):
34
- # type: (Message, ServicerContext) -> Message
39
+ def behavior(request: Message, context: ServicerContext) -> Message:
35
40
  with sentry_sdk.isolation_scope():
36
41
  name = self._find_method_name(context)
37
42
 
@@ -59,6 +64,5 @@ class ServerInterceptor(grpc.ServerInterceptor): # type: ignore
59
64
  )
60
65
 
61
66
  @staticmethod
62
- def _find_name(context):
63
- # type: (ServicerContext) -> str
67
+ def _find_name(context: ServicerContext) -> str:
64
68
  return context._rpc_event.call_details.method.decode()