Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/sentry_sdk/integrations/django/templates.py: 18%
103 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
1from django.template import TemplateSyntaxError
2from django import VERSION as DJANGO_VERSION
4from sentry_sdk import _functools, Hub
5from sentry_sdk._types import MYPY
7if MYPY: 7 ↛ 8line 7 didn't jump to line 8, because the condition on line 7 was never true
8 from typing import Any
9 from typing import Dict
10 from typing import Optional
11 from typing import Iterator
12 from typing import Tuple
14try:
15 # support Django 1.9
16 from django.template.base import Origin
17except ImportError:
18 # backward compatibility
19 from django.template.loader import LoaderOrigin as Origin
22def get_template_frame_from_exception(exc_value):
23 # type: (Optional[BaseException]) -> Optional[Dict[str, Any]]
25 # As of Django 1.9 or so the new template debug thing showed up.
26 if hasattr(exc_value, "template_debug"):
27 return _get_template_frame_from_debug(exc_value.template_debug) # type: ignore
29 # As of r16833 (Django) all exceptions may contain a
30 # ``django_template_source`` attribute (rather than the legacy
31 # ``TemplateSyntaxError.source`` check)
32 if hasattr(exc_value, "django_template_source"):
33 return _get_template_frame_from_source(
34 exc_value.django_template_source # type: ignore
35 )
37 if isinstance(exc_value, TemplateSyntaxError) and hasattr(exc_value, "source"):
38 source = exc_value.source
39 if isinstance(source, (tuple, list)) and isinstance(source[0], Origin):
40 return _get_template_frame_from_source(source) # type: ignore
42 return None
45def _get_template_name_description(template_name):
46 # type: (str) -> str
47 if isinstance(template_name, (list, tuple)):
48 if template_name:
49 return "[{}, ...]".format(template_name[0])
50 else:
51 return template_name
54def patch_templates():
55 # type: () -> None
56 from django.template.response import SimpleTemplateResponse
57 from sentry_sdk.integrations.django import DjangoIntegration
59 real_rendered_content = SimpleTemplateResponse.rendered_content
61 @property # type: ignore
62 def rendered_content(self):
63 # type: (SimpleTemplateResponse) -> str
64 hub = Hub.current
65 if hub.get_integration(DjangoIntegration) is None:
66 return real_rendered_content.fget(self)
68 with hub.start_span(
69 op="django.template.render",
70 description=_get_template_name_description(self.template_name),
71 ) as span:
72 span.set_data("context", self.context_data)
73 return real_rendered_content.fget(self)
75 SimpleTemplateResponse.rendered_content = rendered_content
77 if DJANGO_VERSION < (1, 7): 77 ↛ 78line 77 didn't jump to line 78, because the condition on line 77 was never true
78 return
79 import django.shortcuts
81 real_render = django.shortcuts.render
83 @_functools.wraps(real_render)
84 def render(request, template_name, context=None, *args, **kwargs):
85 # type: (django.http.HttpRequest, str, Optional[Dict[str, Any]], *Any, **Any) -> django.http.HttpResponse
86 hub = Hub.current
87 if hub.get_integration(DjangoIntegration) is None:
88 return real_render(request, template_name, context, *args, **kwargs)
90 with hub.start_span(
91 op="django.template.render",
92 description=_get_template_name_description(template_name),
93 ) as span:
94 span.set_data("context", context)
95 return real_render(request, template_name, context, *args, **kwargs)
97 django.shortcuts.render = render
100def _get_template_frame_from_debug(debug):
101 # type: (Dict[str, Any]) -> Dict[str, Any]
102 if debug is None:
103 return None
105 lineno = debug["line"]
106 filename = debug["name"]
107 if filename is None:
108 filename = "<django template>"
110 pre_context = []
111 post_context = []
112 context_line = None
114 for i, line in debug["source_lines"]:
115 if i < lineno:
116 pre_context.append(line)
117 elif i > lineno:
118 post_context.append(line)
119 else:
120 context_line = line
122 return {
123 "filename": filename,
124 "lineno": lineno,
125 "pre_context": pre_context[-5:],
126 "post_context": post_context[:5],
127 "context_line": context_line,
128 "in_app": True,
129 }
132def _linebreak_iter(template_source):
133 # type: (str) -> Iterator[int]
134 yield 0
135 p = template_source.find("\n")
136 while p >= 0:
137 yield p + 1
138 p = template_source.find("\n", p + 1)
141def _get_template_frame_from_source(source):
142 # type: (Tuple[Origin, Tuple[int, int]]) -> Optional[Dict[str, Any]]
143 if not source:
144 return None
146 origin, (start, end) = source
147 filename = getattr(origin, "loadname", None)
148 if filename is None:
149 filename = "<django template>"
150 template_source = origin.reload()
151 lineno = None
152 upto = 0
153 pre_context = []
154 post_context = []
155 context_line = None
157 for num, next in enumerate(_linebreak_iter(template_source)):
158 line = template_source[upto:next]
159 if start >= upto and end <= next:
160 lineno = num
161 context_line = line
162 elif lineno is None:
163 pre_context.append(line)
164 else:
165 post_context.append(line)
167 upto = next
169 if context_line is None or lineno is None:
170 return None
172 return {
173 "filename": filename,
174 "lineno": lineno,
175 "pre_context": pre_context[-5:],
176 "post_context": post_context[:5],
177 "context_line": context_line,
178 }