Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/sentry_sdk/integrations/django/transactions.py: 79%
69 statements
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
1"""
2Copied from raven-python. Used for
3`DjangoIntegration(transaction_fron="raven_legacy")`.
4"""
6from __future__ import absolute_import
8import re
10from sentry_sdk._types import MYPY
12if MYPY: 12 ↛ 13line 12 didn't jump to line 13, because the condition on line 12 was never true
13 from django.urls.resolvers import URLResolver
14 from typing import Dict
15 from typing import List
16 from typing import Optional
17 from django.urls.resolvers import URLPattern
18 from typing import Tuple
19 from typing import Union
20 from re import Pattern
22try:
23 from django.urls import get_resolver
24except ImportError:
25 from django.core.urlresolvers import get_resolver
28def get_regex(resolver_or_pattern):
29 # type: (Union[URLPattern, URLResolver]) -> Pattern[str]
30 """Utility method for django's deprecated resolver.regex"""
31 try:
32 regex = resolver_or_pattern.regex
33 except AttributeError:
34 regex = resolver_or_pattern.pattern.regex
35 return regex
38class RavenResolver(object):
39 _optional_group_matcher = re.compile(r"\(\?\:([^\)]+)\)")
40 _named_group_matcher = re.compile(r"\(\?P<(\w+)>[^\)]+\)+")
41 _non_named_group_matcher = re.compile(r"\([^\)]+\)")
42 # [foo|bar|baz]
43 _either_option_matcher = re.compile(r"\[([^\]]+)\|([^\]]+)\]")
44 _camel_re = re.compile(r"([A-Z]+)([a-z])")
46 _cache = {} # type: Dict[URLPattern, str]
48 def _simplify(self, pattern):
49 # type: (str) -> str
50 r"""
51 Clean up urlpattern regexes into something readable by humans:
53 From:
54 > "^(?P<sport_slug>\w+)/athletes/(?P<athlete_slug>\w+)/$"
56 To:
57 > "{sport_slug}/athletes/{athlete_slug}/"
58 """
59 # remove optional params
60 # TODO(dcramer): it'd be nice to change these into [%s] but it currently
61 # conflicts with the other rules because we're doing regexp matches
62 # rather than parsing tokens
63 result = self._optional_group_matcher.sub(lambda m: "%s" % m.group(1), pattern) 63 ↛ exitline 63 didn't run the lambda on line 63
65 # handle named groups first
66 result = self._named_group_matcher.sub(lambda m: "{%s}" % m.group(1), result)
68 # handle non-named groups
69 result = self._non_named_group_matcher.sub("{var}", result)
71 # handle optional params
72 result = self._either_option_matcher.sub(lambda m: m.group(1), result) 72 ↛ exitline 72 didn't run the lambda on line 72
74 # clean up any outstanding regex-y characters.
75 result = (
76 result.replace("^", "")
77 .replace("$", "")
78 .replace("?", "")
79 .replace("\\A", "")
80 .replace("\\Z", "")
81 .replace("//", "/")
82 .replace("\\", "")
83 )
85 return result
87 def _resolve(self, resolver, path, parents=None):
88 # type: (URLResolver, str, Optional[List[URLResolver]]) -> Optional[str]
90 match = get_regex(resolver).search(path) # Django < 2.0
92 if not match:
93 return None
95 if parents is None:
96 parents = [resolver]
97 elif resolver not in parents: 97 ↛ 100line 97 didn't jump to line 100, because the condition on line 97 was never false
98 parents = parents + [resolver]
100 new_path = path[match.end() :]
101 for pattern in resolver.url_patterns: 101 ↛ 123line 101 didn't jump to line 123, because the loop on line 101 didn't complete
102 # this is an include()
103 if not pattern.callback:
104 match_ = self._resolve(pattern, new_path, parents)
105 if match_: 105 ↛ 107line 105 didn't jump to line 107, because the condition on line 105 was never false
106 return match_
107 continue
108 elif not get_regex(pattern).search(new_path):
109 continue
111 try:
112 return self._cache[pattern]
113 except KeyError:
114 pass
116 prefix = "".join(self._simplify(get_regex(p).pattern) for p in parents)
117 result = prefix + self._simplify(get_regex(pattern).pattern)
118 if not result.startswith("/"): 118 ↛ 119line 118 didn't jump to line 119, because the condition on line 118 was never true
119 result = "/" + result
120 self._cache[pattern] = result
121 return result
123 return None
125 def resolve(
126 self,
127 path, # type: str
128 urlconf=None, # type: Union[None, Tuple[URLPattern, URLPattern, URLResolver], Tuple[URLPattern]]
129 ):
130 # type: (...) -> str
131 resolver = get_resolver(urlconf)
132 match = self._resolve(resolver, path)
133 return match or path
136LEGACY_RESOLVER = RavenResolver()