From 8fb2d0b5aaffcd4aeb27d0e15f50a52005bcb25f Mon Sep 17 00:00:00 2001 From: Namit Adhikari Date: Tue, 10 Feb 2026 16:00:35 +0545 Subject: [PATCH 1/3] ref(types): add partial type hints for `SamplingContext` --- sentry_sdk/_types.py | 75 ++++++++++++++++++++++++++++++++++++-------- sentry_sdk/scope.py | 2 +- 2 files changed, 63 insertions(+), 14 deletions(-) diff --git a/sentry_sdk/_types.py b/sentry_sdk/_types.py index e5f791fdf0..a9db68628a 100644 --- a/sentry_sdk/_types.py +++ b/sentry_sdk/_types.py @@ -1,6 +1,5 @@ from typing import TYPE_CHECKING, TypeVar, Union - # Re-exported for compat, since code out there in the wild might use this variable. MYPY = TYPE_CHECKING @@ -93,20 +92,14 @@ def substituted_because_contains_sensitive_data(cls) -> "AnnotatedValue": if TYPE_CHECKING: from collections.abc import Container, MutableMapping, Sequence - from datetime import datetime - from types import TracebackType - from typing import Any - from typing import Callable - from typing import Dict - from typing import Mapping - from typing import NotRequired - from typing import Optional - from typing import Tuple - from typing import Type + from typing import Any, Callable, Dict, Mapping, NotRequired, Optional, Type + from typing_extensions import Literal, TypedDict + from sentry_sdk.tracing import TransactionSource + class SDKInfo(TypedDict): name: str version: str @@ -285,8 +278,64 @@ class SDKInfo(TypedDict): # TODO: Make a proper type definition for this (PRs welcome!) BreadcrumbHint = Dict[str, Any] - # TODO: Make a proper type definition for this (PRs welcome!) - SamplingContext = Dict[str, Any] + _ASGIInfo = TypedDict("_ASGIInfo", {"version": str, "spec_version": str}) + _ASGIScope = TypedDict( + "_ASGIScope", + { + "type": str, + "asgi": _ASGIInfo, + "http_version": str, + "server": tuple[str, int], + "client": tuple[str, int], + "scheme": str, + "method": str, + "root_path": str, + "path": str, + "raw_path": bytes, + "query_string": bytes, + "headers": list[tuple[bytes, bytes]], + "state": dict[str, Any], + }, + ) + _TransactionContext = TypedDict( + "_TransactionContext", + { + "trace_id": str, + "span_id": str, + "parent_span_id": Optional[str], + "same_process_as_parent": bool, + "op": Optional[str], + "description": Optional[str], + "start_timestamp": datetime | int, + "timestamp": Optional[datetime], + "origin": str, + "tags": NotRequired[dict[str, str]], + "data": dict[str, Any], + "name": str, + "source": TransactionSource, + "sampled": Optional[bool], + }, + ) + _SamplingContextTyped = TypedDict( + "_SamplingContextTyped", + { + "transaction_context": _TransactionContext, + "parent_sampled": Optional[bool], + "asgi_scope": NotRequired[_ASGIScope], + # `wsgi_environ` is only present for WSGI server (like Django), and it contains mainly env vars, and some wsgi specifics. + "wsgi_environ": NotRequired[dict[str, Any]], + # `aiohttp_request` is only present for AIOHTTP server, and contains + "aiohttp_request": NotRequired[Any], + # NOT tested these below, but documented for completeness sake to pass mypy. + "tornado_request": NotRequired[Any], + "celery_job": NotRequired[dict[str, Any]], + "rq_job": NotRequired[Any], + "aws_event": NotRequired[Any], + "aws_context": NotRequired[Any], + "gcp_env": NotRequired[dict[str, Any]], + }, + ) + SamplingContext = Union[_SamplingContextTyped, dict[str, Any]] EventProcessor = Callable[[Event, Hint], Optional[Event]] ErrorProcessor = Callable[[Event, ExcInfo], Optional[Event]] diff --git a/sentry_sdk/scope.py b/sentry_sdk/scope.py index 3bc51c1af0..2a95c5e2e9 100644 --- a/sentry_sdk/scope.py +++ b/sentry_sdk/scope.py @@ -1076,7 +1076,7 @@ def start_transaction( # use traces_sample_rate, traces_sampler, and/or inheritance to make a # sampling decision - sampling_context = { + sampling_context: "Dict[str, Any]" = { "transaction_context": transaction.to_json(), "parent_sampled": transaction.parent_sampled, } From 859efe2cf1e347e54eb74b870db5ac548b41f015 Mon Sep 17 00:00:00 2001 From: Namit Adhikari Date: Tue, 10 Feb 2026 20:06:44 +0545 Subject: [PATCH 2/3] ref(types): make TransactionContext.data field optional in SamplingContext --- sentry_sdk/_types.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sentry_sdk/_types.py b/sentry_sdk/_types.py index a9db68628a..bc74503b7d 100644 --- a/sentry_sdk/_types.py +++ b/sentry_sdk/_types.py @@ -310,7 +310,7 @@ class SDKInfo(TypedDict): "timestamp": Optional[datetime], "origin": str, "tags": NotRequired[dict[str, str]], - "data": dict[str, Any], + "data": NotRequired[dict[str, Any]], "name": str, "source": TransactionSource, "sampled": Optional[bool], @@ -333,6 +333,7 @@ class SDKInfo(TypedDict): "aws_event": NotRequired[Any], "aws_context": NotRequired[Any], "gcp_env": NotRequired[dict[str, Any]], + "gcp_event": NotRequired[Any], }, ) SamplingContext = Union[_SamplingContextTyped, dict[str, Any]] From b1d3de3e229ccc34f9ad1d022208aae6ddad0ac7 Mon Sep 17 00:00:00 2001 From: Namit Adhikari Date: Tue, 10 Feb 2026 20:13:54 +0545 Subject: [PATCH 3/3] ref(types): make ASGI Scope fields NotRequired as per official ASGI Spec --- sentry_sdk/_types.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/sentry_sdk/_types.py b/sentry_sdk/_types.py index bc74503b7d..45140f11f3 100644 --- a/sentry_sdk/_types.py +++ b/sentry_sdk/_types.py @@ -285,16 +285,17 @@ class SDKInfo(TypedDict): "type": str, "asgi": _ASGIInfo, "http_version": str, - "server": tuple[str, int], - "client": tuple[str, int], - "scheme": str, "method": str, - "root_path": str, "path": str, - "raw_path": bytes, "query_string": bytes, "headers": list[tuple[bytes, bytes]], - "state": dict[str, Any], + # Optional fields per ASGI spec + "scheme": NotRequired[str], + "raw_path": NotRequired[bytes], + "root_path": NotRequired[str], + "client": NotRequired[tuple[str, int]], + "server": NotRequired[tuple[str, int]], + "state": NotRequired[dict[str, Any]], }, ) _TransactionContext = TypedDict(