diff --git a/pyproject.toml b/pyproject.toml index 881e43a105..520f33f168 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -67,6 +67,7 @@ typing = [ "httpx2", "botocore-stubs", "werkzeug", + "starlette>=1.3.1", ] test = [ "dataclasses ; python_full_version < '3.7'", diff --git a/sentry_sdk/integrations/mcp.py b/sentry_sdk/integrations/mcp.py index 7ec7a22c21..e59c40feb3 100644 --- a/sentry_sdk/integrations/mcp.py +++ b/sentry_sdk/integrations/mcp.py @@ -55,7 +55,7 @@ if TYPE_CHECKING: from typing import Any, Callable, ContextManager, Optional, Tuple, Union - from starlette.types import Receive, Scope, Send # type: ignore[import-not-found] + from starlette.types import Receive, Scope, Send from sentry_sdk.traces import StreamedSpan from sentry_sdk.tracing import Span diff --git a/sentry_sdk/integrations/starlette.py b/sentry_sdk/integrations/starlette.py index eccb4f780f..8b1e485d9e 100644 --- a/sentry_sdk/integrations/starlette.py +++ b/sentry_sdk/integrations/starlette.py @@ -40,31 +40,39 @@ ) if TYPE_CHECKING: - from typing import Any, Awaitable, Callable, Container, Dict, Optional, Tuple, Union + from typing import ( + Any, + Awaitable, + Callable, + Container, + Dict, + Optional, + Tuple, + Union, + ) from sentry_sdk._types import Event, HttpStatusCodeRange - try: - import starlette # type: ignore + import starlette from starlette import __version__ as STARLETTE_VERSION - from starlette.applications import Starlette # type: ignore - from starlette.datastructures import ( # type: ignore + from starlette.applications import Starlette + from starlette.datastructures import ( UploadFile, ) - from starlette.middleware import Middleware # type: ignore - from starlette.middleware.authentication import ( # type: ignore + from starlette.middleware import Middleware + from starlette.middleware.authentication import ( AuthenticationMiddleware, ) - from starlette.requests import Request # type: ignore - from starlette.routing import Match # type: ignore - from starlette.types import ASGIApp, Receive, Send # type: ignore + from starlette.requests import Request + from starlette.routing import Match + from starlette.types import ASGIApp, Receive, Send from starlette.types import Scope as StarletteScope except ImportError: raise DidNotEnable("Starlette is not installed") try: # Starlette 0.20 - from starlette.middleware.exceptions import ExceptionMiddleware # type: ignore + from starlette.middleware.exceptions import ExceptionMiddleware except ImportError: # Startlette 0.19.1 from starlette.exceptions import ExceptionMiddleware # type: ignore @@ -156,8 +164,10 @@ def setup_once() -> None: patch_templates() -def _enable_span_for_middleware(middleware_class: "Any") -> type: - old_call = middleware_class.__call__ +def _enable_span_for_middleware( + middleware_class: "Any", +) -> "Any": + old_call: "Callable[..., Awaitable[Any]]" = middleware_class.__call__ async def _create_span_call( app: "Any", @@ -430,7 +440,7 @@ def _sentry_middleware_init( if cls == ExceptionMiddleware: patch_exception_middleware(cls) - Middleware.__init__ = _sentry_middleware_init + Middleware.__init__ = _sentry_middleware_init # type: ignore[method-assign] def patch_asgi_app(root_path_in_path: "_RootPathInPath") -> None: @@ -462,7 +472,7 @@ async def _sentry_patched_asgi_app( return await middleware(scope, receive, send) - Starlette.__call__ = _sentry_patched_asgi_app + Starlette.__call__ = _sentry_patched_asgi_app # type: ignore[method-assign] # This was vendored in from Starlette to support Starlette 0.19.1 because @@ -662,7 +672,7 @@ def patch_templates() -> None: # https://github.com/Kludex/starlette/commit/96479daca2e4bd8157f68d914fd162aa94eff73a try: - from starlette.templating import Jinja2Templates # type: ignore + from starlette.templating import Jinja2Templates except ImportError: return @@ -692,7 +702,7 @@ def add_sentry_trace_meta(request: "Request") -> "Dict[str, Any]": return old_jinja2templates_init(self, *args, **kwargs) - Jinja2Templates.__init__ = _sentry_jinja2templates_init + Jinja2Templates.__init__ = _sentry_jinja2templates_init # type: ignore[method-assign] class StarletteRequestExtractor: @@ -701,8 +711,6 @@ class StarletteRequestExtractor: (like form data or cookies) and adds it to the Sentry event. """ - request: "Request" = None - def __init__(self: "StarletteRequestExtractor", request: "Request") -> None: self.request = request diff --git a/uv.lock b/uv.lock index 4addd76e84..09742b6d5a 100644 --- a/uv.lock +++ b/uv.lock @@ -51,6 +51,7 @@ typing = [ { name = "openfeature-sdk" }, { name = "opentelemetry-distro", extras = ["otlp"] }, { name = "pymongo" }, + { name = "starlette", specifier = ">=1.3.1" }, { name = "statsig" }, { name = "strawberry-graphql" }, { name = "typer" }, @@ -1618,6 +1619,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/52/a7/d2782e4e3f77c8450f727ba74a8f12756d5ba823d81b941f1b04da9d033a/sphinxcontrib_serializinghtml-2.0.0-py3-none-any.whl", hash = "sha256:6e2cb0eef194e10c27ec0023bfeb25badbbb5868244cf5bc5bdc04e4464bf331", size = 92072, upload-time = "2024-07-29T01:10:08.203Z" }, ] +[[package]] +name = "starlette" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/eb/e3/7c1dc7381d9f8ab7d854328ebfa884e62cb3f3d8549ddfd37c7814f42afa/starlette-1.3.1.tar.gz", hash = "sha256:05d0213193f2fbaae60e2ecb593b4add4262ad4e46536b54abe36f11a71724e0", size = 2703240, upload-time = "2026-06-12T09:23:11.602Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl", hash = "sha256:c7372aae11c3c3f26a42df7bd626cec2f47d03483d261d369516a615a53714c6", size = 73632, upload-time = "2026-06-12T09:23:10.017Z" }, +] + [[package]] name = "statsig" version = "0.71.6"