Skip to content

Commit 5d89fa7

Browse files
untitakersentry-bot
and
sentry-bot
authored
fix(django): Do not patch resolver_match (getsentry#842)
Co-authored-by: sentry-bot <markus+ghbot@sentry.io>
1 parent cdf21de commit 5d89fa7

File tree

3 files changed

+30
-49
lines changed

3 files changed

+30
-49
lines changed

sentry_sdk/integrations/django/__init__.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
from sentry_sdk.integrations.django.transactions import LEGACY_RESOLVER
4040
from sentry_sdk.integrations.django.templates import get_template_frame_from_exception
4141
from sentry_sdk.integrations.django.middleware import patch_django_middlewares
42-
from sentry_sdk.integrations.django.views import patch_resolver
42+
from sentry_sdk.integrations.django.views import patch_views
4343

4444

4545
if MYPY:
@@ -200,7 +200,7 @@ def _django_queryset_repr(value, hint):
200200

201201
_patch_channels()
202202
patch_django_middlewares()
203-
patch_resolver()
203+
patch_views()
204204

205205

206206
_DRF_PATCHED = False

sentry_sdk/integrations/django/views.py

+23-47
Original file line numberDiff line numberDiff line change
@@ -5,63 +5,39 @@
55
if MYPY:
66
from typing import Any
77

8-
from django.urls.resolvers import ResolverMatch
98

10-
11-
def patch_resolver():
9+
def patch_views():
1210
# type: () -> None
13-
try:
14-
from django.urls.resolvers import URLResolver
15-
except ImportError:
16-
try:
17-
from django.urls.resolvers import RegexURLResolver as URLResolver
18-
except ImportError:
19-
from django.core.urlresolvers import RegexURLResolver as URLResolver
2011

12+
from django.core.handlers.base import BaseHandler
2113
from sentry_sdk.integrations.django import DjangoIntegration
2214

23-
old_resolve = URLResolver.resolve
24-
25-
def resolve(self, path):
26-
# type: (URLResolver, Any) -> ResolverMatch
27-
hub = Hub.current
28-
integration = hub.get_integration(DjangoIntegration)
29-
30-
if integration is None or not integration.middleware_spans:
31-
return old_resolve(self, path)
15+
old_make_view_atomic = BaseHandler.make_view_atomic
3216

33-
return _wrap_resolver_match(hub, old_resolve(self, path))
17+
@_functools.wraps(old_make_view_atomic)
18+
def sentry_patched_make_view_atomic(self, *args, **kwargs):
19+
# type: (Any, *Any, **Any) -> Any
20+
callback = old_make_view_atomic(self, *args, **kwargs)
3421

35-
URLResolver.resolve = resolve
22+
# XXX: The wrapper function is created for every request. Find more
23+
# efficient way to wrap views (or build a cache?)
3624

25+
hub = Hub.current
26+
integration = hub.get_integration(DjangoIntegration)
3727

38-
def _wrap_resolver_match(hub, resolver_match):
39-
# type: (Hub, ResolverMatch) -> ResolverMatch
40-
41-
# XXX: The wrapper function is created for every request. Find more
42-
# efficient way to wrap views (or build a cache?)
43-
44-
old_callback = resolver_match.func
28+
if integration is not None and integration.middleware_spans:
4529

46-
# Explicitly forward `csrf_exempt` in case it is not an attribute in
47-
# callback.__dict__, but rather a class attribute (on a class
48-
# implementing __call__) such as this:
49-
#
50-
# class Foo(object):
51-
# csrf_exempt = True
52-
#
53-
# def __call__(self, request): ...
54-
#
55-
# We have had this in the Sentry codebase (for no good reason, but
56-
# nevertheless we broke user code)
57-
assigned = _functools.WRAPPER_ASSIGNMENTS + ("csrf_exempt",)
30+
@_functools.wraps(callback)
31+
def sentry_wrapped_callback(request, *args, **kwargs):
32+
# type: (Any, *Any, **Any) -> Any
33+
with hub.start_span(
34+
op="django.view", description=request.resolver_match.view_name
35+
):
36+
return callback(request, *args, **kwargs)
5837

59-
@_functools.wraps(old_callback, assigned=assigned)
60-
def callback(*args, **kwargs):
61-
# type: (*Any, **Any) -> Any
62-
with hub.start_span(op="django.view", description=resolver_match.view_name):
63-
return old_callback(*args, **kwargs)
38+
else:
39+
sentry_wrapped_callback = callback
6440

65-
resolver_match.func = callback
41+
return sentry_wrapped_callback
6642

67-
return resolver_match
43+
BaseHandler.make_view_atomic = sentry_patched_make_view_atomic

tests/integrations/django/myapp/settings.py

+5
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,11 @@
5959

6060
class TestMiddleware(MiddlewareMixin):
6161
def process_request(self, request):
62+
# https://github.com/getsentry/sentry-python/issues/837 -- We should
63+
# not touch the resolver_match because apparently people rely on it.
64+
if request.resolver_match:
65+
assert not getattr(request.resolver_match.callback, "__wrapped__", None)
66+
6267
if "middleware-exc" in request.path:
6368
1 / 0
6469

0 commit comments

Comments
 (0)