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

1from django.template import TemplateSyntaxError 

2from django import VERSION as DJANGO_VERSION 

3 

4from sentry_sdk import _functools, Hub 

5from sentry_sdk._types import MYPY 

6 

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 

13 

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 

20 

21 

22def get_template_frame_from_exception(exc_value): 

23 # type: (Optional[BaseException]) -> Optional[Dict[str, Any]] 

24 

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 

28 

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 ) 

36 

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 

41 

42 return None 

43 

44 

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 

52 

53 

54def patch_templates(): 

55 # type: () -> None 

56 from django.template.response import SimpleTemplateResponse 

57 from sentry_sdk.integrations.django import DjangoIntegration 

58 

59 real_rendered_content = SimpleTemplateResponse.rendered_content 

60 

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) 

67 

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) 

74 

75 SimpleTemplateResponse.rendered_content = rendered_content 

76 

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 

80 

81 real_render = django.shortcuts.render 

82 

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) 

89 

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) 

96 

97 django.shortcuts.render = render 

98 

99 

100def _get_template_frame_from_debug(debug): 

101 # type: (Dict[str, Any]) -> Dict[str, Any] 

102 if debug is None: 

103 return None 

104 

105 lineno = debug["line"] 

106 filename = debug["name"] 

107 if filename is None: 

108 filename = "<django template>" 

109 

110 pre_context = [] 

111 post_context = [] 

112 context_line = None 

113 

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 

121 

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 } 

130 

131 

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) 

139 

140 

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 

145 

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 

156 

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) 

166 

167 upto = next 

168 

169 if context_line is None or lineno is None: 

170 return None 

171 

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 }