Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/django/forms/utils.py: 43%

108 statements  

« prev     ^ index     » next       coverage.py v6.4.4, created at 2023-07-17 14:22 -0600

1import json 

2from collections import UserList 

3 

4from django.conf import settings 

5from django.core.exceptions import ValidationError 

6from django.forms.renderers import get_default_renderer 

7from django.utils import timezone 

8from django.utils.html import escape, format_html_join 

9from django.utils.safestring import mark_safe 

10from django.utils.translation import gettext_lazy as _ 

11 

12 

13def pretty_name(name): 

14 """Convert 'first_name' to 'First name'.""" 

15 if not name: 15 ↛ 16line 15 didn't jump to line 16, because the condition on line 15 was never true

16 return "" 

17 return name.replace("_", " ").capitalize() 

18 

19 

20def flatatt(attrs): 

21 """ 

22 Convert a dictionary of attributes to a single string. 

23 The returned string will contain a leading space followed by key="value", 

24 XML-style pairs. In the case of a boolean value, the key will appear 

25 without a value. It is assumed that the keys do not need to be 

26 XML-escaped. If the passed dictionary is empty, then return an empty 

27 string. 

28 

29 The result is passed through 'mark_safe' (by way of 'format_html_join'). 

30 """ 

31 key_value_attrs = [] 

32 boolean_attrs = [] 

33 for attr, value in attrs.items(): 

34 if isinstance(value, bool): 

35 if value: 

36 boolean_attrs.append((attr,)) 

37 elif value is not None: 

38 key_value_attrs.append((attr, value)) 

39 

40 return format_html_join("", ' {}="{}"', sorted(key_value_attrs)) + format_html_join( 

41 "", " {}", sorted(boolean_attrs) 

42 ) 

43 

44 

45class RenderableMixin: 

46 def get_context(self): 

47 raise NotImplementedError( 

48 "Subclasses of RenderableMixin must provide a get_context() method." 

49 ) 

50 

51 def render(self, template_name=None, context=None, renderer=None): 

52 return mark_safe( 

53 (renderer or self.renderer).render( 

54 template_name or self.template_name, 

55 context or self.get_context(), 

56 ) 

57 ) 

58 

59 __str__ = render 

60 __html__ = render 

61 

62 

63class RenderableFormMixin(RenderableMixin): 

64 def as_p(self): 

65 """Render as <p> elements.""" 

66 return self.render(self.template_name_p) 

67 

68 def as_table(self): 

69 """Render as <tr> elements excluding the surrounding <table> tag.""" 

70 return self.render(self.template_name_table) 

71 

72 def as_ul(self): 

73 """Render as <li> elements excluding the surrounding <ul> tag.""" 

74 return self.render(self.template_name_ul) 

75 

76 

77class RenderableErrorMixin(RenderableMixin): 

78 def as_json(self, escape_html=False): 

79 return json.dumps(self.get_json_data(escape_html)) 

80 

81 def as_text(self): 

82 return self.render(self.template_name_text) 

83 

84 def as_ul(self): 

85 return self.render(self.template_name_ul) 

86 

87 

88class ErrorDict(dict, RenderableErrorMixin): 

89 """ 

90 A collection of errors that knows how to display itself in various formats. 

91 

92 The dictionary keys are the field names, and the values are the errors. 

93 """ 

94 

95 template_name = "django/forms/errors/dict/default.html" 

96 template_name_text = "django/forms/errors/dict/text.txt" 

97 template_name_ul = "django/forms/errors/dict/ul.html" 

98 

99 def __init__(self, *args, renderer=None, **kwargs): 

100 super().__init__(*args, **kwargs) 

101 self.renderer = renderer or get_default_renderer() 

102 

103 def as_data(self): 

104 return {f: e.as_data() for f, e in self.items()} 

105 

106 def get_json_data(self, escape_html=False): 

107 return {f: e.get_json_data(escape_html) for f, e in self.items()} 

108 

109 def get_context(self): 

110 return { 

111 "errors": self.items(), 

112 "error_class": "errorlist", 

113 } 

114 

115 

116class ErrorList(UserList, list, RenderableErrorMixin): 

117 """ 

118 A collection of errors that knows how to display itself in various formats. 

119 """ 

120 

121 template_name = "django/forms/errors/list/default.html" 

122 template_name_text = "django/forms/errors/list/text.txt" 

123 template_name_ul = "django/forms/errors/list/ul.html" 

124 

125 def __init__(self, initlist=None, error_class=None, renderer=None): 

126 super().__init__(initlist) 

127 

128 if error_class is None: 

129 self.error_class = "errorlist" 

130 else: 

131 self.error_class = "errorlist {}".format(error_class) 

132 self.renderer = renderer or get_default_renderer() 

133 

134 def as_data(self): 

135 return ValidationError(self.data).error_list 

136 

137 def copy(self): 

138 copy = super().copy() 

139 copy.error_class = self.error_class 

140 return copy 

141 

142 def get_json_data(self, escape_html=False): 

143 errors = [] 

144 for error in self.as_data(): 

145 message = next(iter(error)) 

146 errors.append( 

147 { 

148 "message": escape(message) if escape_html else message, 

149 "code": error.code or "", 

150 } 

151 ) 

152 return errors 

153 

154 def get_context(self): 

155 return { 

156 "errors": self, 

157 "error_class": self.error_class, 

158 } 

159 

160 def __repr__(self): 

161 return repr(list(self)) 

162 

163 def __contains__(self, item): 

164 return item in list(self) 

165 

166 def __eq__(self, other): 

167 return list(self) == other 

168 

169 def __getitem__(self, i): 

170 error = self.data[i] 

171 if isinstance(error, ValidationError): 

172 return next(iter(error)) 

173 return error 

174 

175 def __reduce_ex__(self, *args, **kwargs): 

176 # The `list` reduce function returns an iterator as the fourth element 

177 # that is normally used for repopulating. Since we only inherit from 

178 # `list` for `isinstance` backward compatibility (Refs #17413) we 

179 # nullify this iterator as it would otherwise result in duplicate 

180 # entries. (Refs #23594) 

181 info = super(UserList, self).__reduce_ex__(*args, **kwargs) 

182 return info[:3] + (None, None) 

183 

184 

185# Utilities for time zone support in DateTimeField et al. 

186 

187 

188def from_current_timezone(value): 

189 """ 

190 When time zone support is enabled, convert naive datetimes 

191 entered in the current time zone to aware datetimes. 

192 """ 

193 if settings.USE_TZ and value is not None and timezone.is_naive(value): 

194 current_timezone = timezone.get_current_timezone() 

195 try: 

196 if not timezone._is_pytz_zone( 

197 current_timezone 

198 ) and timezone._datetime_ambiguous_or_imaginary(value, current_timezone): 

199 raise ValueError("Ambiguous or non-existent time.") 

200 return timezone.make_aware(value, current_timezone) 

201 except Exception as exc: 

202 raise ValidationError( 

203 _( 

204 "%(datetime)s couldn’t be interpreted " 

205 "in time zone %(current_timezone)s; it " 

206 "may be ambiguous or it may not exist." 

207 ), 

208 code="ambiguous_timezone", 

209 params={"datetime": value, "current_timezone": current_timezone}, 

210 ) from exc 

211 return value 

212 

213 

214def to_current_timezone(value): 

215 """ 

216 When time zone support is enabled, convert aware datetimes 

217 to naive datetimes in the current time zone for display. 

218 """ 

219 if settings.USE_TZ and value is not None and timezone.is_aware(value): 

220 return timezone.make_naive(value) 

221 return value