Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/email/_policybase.py: 24%

116 statements  

« prev     ^ index     » next       coverage.py v7.0.1, created at 2022-12-25 06:11 +0000

1"""Policy framework for the email package. 

2 

3Allows fine grained feature control of how the package parses and emits data. 

4""" 

5 

6import abc 

7from email import header 

8from email import charset as _charset 

9from email.utils import _has_surrogates 

10 

11__all__ = [ 

12 'Policy', 

13 'Compat32', 

14 'compat32', 

15 ] 

16 

17 

18class _PolicyBase: 

19 

20 """Policy Object basic framework. 

21 

22 This class is useless unless subclassed. A subclass should define 

23 class attributes with defaults for any values that are to be 

24 managed by the Policy object. The constructor will then allow 

25 non-default values to be set for these attributes at instance 

26 creation time. The instance will be callable, taking these same 

27 attributes keyword arguments, and returning a new instance 

28 identical to the called instance except for those values changed 

29 by the keyword arguments. Instances may be added, yielding new 

30 instances with any non-default values from the right hand 

31 operand overriding those in the left hand operand. That is, 

32 

33 A + B == A(<non-default values of B>) 

34 

35 The repr of an instance can be used to reconstruct the object 

36 if and only if the repr of the values can be used to reconstruct 

37 those values. 

38 

39 """ 

40 

41 def __init__(self, **kw): 

42 """Create new Policy, possibly overriding some defaults. 

43 

44 See class docstring for a list of overridable attributes. 

45 

46 """ 

47 for name, value in kw.items(): 

48 if hasattr(self, name): 

49 super(_PolicyBase,self).__setattr__(name, value) 

50 else: 

51 raise TypeError( 

52 "{!r} is an invalid keyword argument for {}".format( 

53 name, self.__class__.__name__)) 

54 

55 def __repr__(self): 

56 args = [ "{}={!r}".format(name, value) 

57 for name, value in self.__dict__.items() ] 

58 return "{}({})".format(self.__class__.__name__, ', '.join(args)) 

59 

60 def clone(self, **kw): 

61 """Return a new instance with specified attributes changed. 

62 

63 The new instance has the same attribute values as the current object, 

64 except for the changes passed in as keyword arguments. 

65 

66 """ 

67 newpolicy = self.__class__.__new__(self.__class__) 

68 for attr, value in self.__dict__.items(): 

69 object.__setattr__(newpolicy, attr, value) 

70 for attr, value in kw.items(): 

71 if not hasattr(self, attr): 

72 raise TypeError( 

73 "{!r} is an invalid keyword argument for {}".format( 

74 attr, self.__class__.__name__)) 

75 object.__setattr__(newpolicy, attr, value) 

76 return newpolicy 

77 

78 def __setattr__(self, name, value): 

79 if hasattr(self, name): 

80 msg = "{!r} object attribute {!r} is read-only" 

81 else: 

82 msg = "{!r} object has no attribute {!r}" 

83 raise AttributeError(msg.format(self.__class__.__name__, name)) 

84 

85 def __add__(self, other): 

86 """Non-default values from right operand override those from left. 

87 

88 The object returned is a new instance of the subclass. 

89 

90 """ 

91 return self.clone(**other.__dict__) 

92 

93 

94def _append_doc(doc, added_doc): 

95 doc = doc.rsplit('\n', 1)[0] 

96 added_doc = added_doc.split('\n', 1)[1] 

97 return doc + '\n' + added_doc 

98 

99def _extend_docstrings(cls): 

100 if cls.__doc__ and cls.__doc__.startswith('+'): 

101 cls.__doc__ = _append_doc(cls.__bases__[0].__doc__, cls.__doc__) 

102 for name, attr in cls.__dict__.items(): 

103 if attr.__doc__ and attr.__doc__.startswith('+'): 

104 for c in (c for base in cls.__bases__ for c in base.mro()): 

105 doc = getattr(getattr(c, name), '__doc__') 

106 if doc: 

107 attr.__doc__ = _append_doc(doc, attr.__doc__) 

108 break 

109 return cls 

110 

111 

112class Policy(_PolicyBase, metaclass=abc.ABCMeta): 

113 

114 r"""Controls for how messages are interpreted and formatted. 

115 

116 Most of the classes and many of the methods in the email package accept 

117 Policy objects as parameters. A Policy object contains a set of values and 

118 functions that control how input is interpreted and how output is rendered. 

119 For example, the parameter 'raise_on_defect' controls whether or not an RFC 

120 violation results in an error being raised or not, while 'max_line_length' 

121 controls the maximum length of output lines when a Message is serialized. 

122 

123 Any valid attribute may be overridden when a Policy is created by passing 

124 it as a keyword argument to the constructor. Policy objects are immutable, 

125 but a new Policy object can be created with only certain values changed by 

126 calling the Policy instance with keyword arguments. Policy objects can 

127 also be added, producing a new Policy object in which the non-default 

128 attributes set in the right hand operand overwrite those specified in the 

129 left operand. 

130 

131 Settable attributes: 

132 

133 raise_on_defect -- If true, then defects should be raised as errors. 

134 Default: False. 

135 

136 linesep -- string containing the value to use as separation 

137 between output lines. Default '\n'. 

138 

139 cte_type -- Type of allowed content transfer encodings 

140 

141 7bit -- ASCII only 

142 8bit -- Content-Transfer-Encoding: 8bit is allowed 

143 

144 Default: 8bit. Also controls the disposition of 

145 (RFC invalid) binary data in headers; see the 

146 documentation of the binary_fold method. 

147 

148 max_line_length -- maximum length of lines, excluding 'linesep', 

149 during serialization. None or 0 means no line 

150 wrapping is done. Default is 78. 

151 

152 mangle_from_ -- a flag that, when True escapes From_ lines in the 

153 body of the message by putting a `>' in front of 

154 them. This is used when the message is being 

155 serialized by a generator. Default: True. 

156 

157 message_factory -- the class to use to create new message objects. 

158 If the value is None, the default is Message. 

159 

160 """ 

161 

162 raise_on_defect = False 

163 linesep = '\n' 

164 cte_type = '8bit' 

165 max_line_length = 78 

166 mangle_from_ = False 

167 message_factory = None 

168 

169 def handle_defect(self, obj, defect): 

170 """Based on policy, either raise defect or call register_defect. 

171 

172 handle_defect(obj, defect) 

173 

174 defect should be a Defect subclass, but in any case must be an 

175 Exception subclass. obj is the object on which the defect should be 

176 registered if it is not raised. If the raise_on_defect is True, the 

177 defect is raised as an error, otherwise the object and the defect are 

178 passed to register_defect. 

179 

180 This method is intended to be called by parsers that discover defects. 

181 The email package parsers always call it with Defect instances. 

182 

183 """ 

184 if self.raise_on_defect: 

185 raise defect 

186 self.register_defect(obj, defect) 

187 

188 def register_defect(self, obj, defect): 

189 """Record 'defect' on 'obj'. 

190 

191 Called by handle_defect if raise_on_defect is False. This method is 

192 part of the Policy API so that Policy subclasses can implement custom 

193 defect handling. The default implementation calls the append method of 

194 the defects attribute of obj. The objects used by the email package by 

195 default that get passed to this method will always have a defects 

196 attribute with an append method. 

197 

198 """ 

199 obj.defects.append(defect) 

200 

201 def header_max_count(self, name): 

202 """Return the maximum allowed number of headers named 'name'. 

203 

204 Called when a header is added to a Message object. If the returned 

205 value is not 0 or None, and there are already a number of headers with 

206 the name 'name' equal to the value returned, a ValueError is raised. 

207 

208 Because the default behavior of Message's __setitem__ is to append the 

209 value to the list of headers, it is easy to create duplicate headers 

210 without realizing it. This method allows certain headers to be limited 

211 in the number of instances of that header that may be added to a 

212 Message programmatically. (The limit is not observed by the parser, 

213 which will faithfully produce as many headers as exist in the message 

214 being parsed.) 

215 

216 The default implementation returns None for all header names. 

217 """ 

218 return None 

219 

220 @abc.abstractmethod 

221 def header_source_parse(self, sourcelines): 

222 """Given a list of linesep terminated strings constituting the lines of 

223 a single header, return the (name, value) tuple that should be stored 

224 in the model. The input lines should retain their terminating linesep 

225 characters. The lines passed in by the email package may contain 

226 surrogateescaped binary data. 

227 """ 

228 raise NotImplementedError 

229 

230 @abc.abstractmethod 

231 def header_store_parse(self, name, value): 

232 """Given the header name and the value provided by the application 

233 program, return the (name, value) that should be stored in the model. 

234 """ 

235 raise NotImplementedError 

236 

237 @abc.abstractmethod 

238 def header_fetch_parse(self, name, value): 

239 """Given the header name and the value from the model, return the value 

240 to be returned to the application program that is requesting that 

241 header. The value passed in by the email package may contain 

242 surrogateescaped binary data if the lines were parsed by a BytesParser. 

243 The returned value should not contain any surrogateescaped data. 

244 

245 """ 

246 raise NotImplementedError 

247 

248 @abc.abstractmethod 

249 def fold(self, name, value): 

250 """Given the header name and the value from the model, return a string 

251 containing linesep characters that implement the folding of the header 

252 according to the policy controls. The value passed in by the email 

253 package may contain surrogateescaped binary data if the lines were 

254 parsed by a BytesParser. The returned value should not contain any 

255 surrogateescaped data. 

256 

257 """ 

258 raise NotImplementedError 

259 

260 @abc.abstractmethod 

261 def fold_binary(self, name, value): 

262 """Given the header name and the value from the model, return binary 

263 data containing linesep characters that implement the folding of the 

264 header according to the policy controls. The value passed in by the 

265 email package may contain surrogateescaped binary data. 

266 

267 """ 

268 raise NotImplementedError 

269 

270 

271@_extend_docstrings 

272class Compat32(Policy): 

273 

274 """+ 

275 This particular policy is the backward compatibility Policy. It 

276 replicates the behavior of the email package version 5.1. 

277 """ 

278 

279 mangle_from_ = True 

280 

281 def _sanitize_header(self, name, value): 

282 # If the header value contains surrogates, return a Header using 

283 # the unknown-8bit charset to encode the bytes as encoded words. 

284 if not isinstance(value, str): 

285 # Assume it is already a header object 

286 return value 

287 if _has_surrogates(value): 

288 return header.Header(value, charset=_charset.UNKNOWN8BIT, 

289 header_name=name) 

290 else: 

291 return value 

292 

293 def header_source_parse(self, sourcelines): 

294 """+ 

295 The name is parsed as everything up to the ':' and returned unmodified. 

296 The value is determined by stripping leading whitespace off the 

297 remainder of the first line, joining all subsequent lines together, and 

298 stripping any trailing carriage return or linefeed characters. 

299 

300 """ 

301 name, value = sourcelines[0].split(':', 1) 

302 value = value.lstrip(' \t') + ''.join(sourcelines[1:]) 

303 return (name, value.rstrip('\r\n')) 

304 

305 def header_store_parse(self, name, value): 

306 """+ 

307 The name and value are returned unmodified. 

308 """ 

309 return (name, value) 

310 

311 def header_fetch_parse(self, name, value): 

312 """+ 

313 If the value contains binary data, it is converted into a Header object 

314 using the unknown-8bit charset. Otherwise it is returned unmodified. 

315 """ 

316 return self._sanitize_header(name, value) 

317 

318 def fold(self, name, value): 

319 """+ 

320 Headers are folded using the Header folding algorithm, which preserves 

321 existing line breaks in the value, and wraps each resulting line to the 

322 max_line_length. Non-ASCII binary data are CTE encoded using the 

323 unknown-8bit charset. 

324 

325 """ 

326 return self._fold(name, value, sanitize=True) 

327 

328 def fold_binary(self, name, value): 

329 """+ 

330 Headers are folded using the Header folding algorithm, which preserves 

331 existing line breaks in the value, and wraps each resulting line to the 

332 max_line_length. If cte_type is 7bit, non-ascii binary data is CTE 

333 encoded using the unknown-8bit charset. Otherwise the original source 

334 header is used, with its existing line breaks and/or binary data. 

335 

336 """ 

337 folded = self._fold(name, value, sanitize=self.cte_type=='7bit') 

338 return folded.encode('ascii', 'surrogateescape') 

339 

340 def _fold(self, name, value, sanitize): 

341 parts = [] 

342 parts.append('%s: ' % name) 

343 if isinstance(value, str): 

344 if _has_surrogates(value): 

345 if sanitize: 

346 h = header.Header(value, 

347 charset=_charset.UNKNOWN8BIT, 

348 header_name=name) 

349 else: 

350 # If we have raw 8bit data in a byte string, we have no idea 

351 # what the encoding is. There is no safe way to split this 

352 # string. If it's ascii-subset, then we could do a normal 

353 # ascii split, but if it's multibyte then we could break the 

354 # string. There's no way to know so the least harm seems to 

355 # be to not split the string and risk it being too long. 

356 parts.append(value) 

357 h = None 

358 else: 

359 h = header.Header(value, header_name=name) 

360 else: 

361 # Assume it is a Header-like object. 

362 h = value 

363 if h is not None: 

364 # The Header class interprets a value of None for maxlinelen as the 

365 # default value of 78, as recommended by RFC 2822. 

366 maxlinelen = 0 

367 if self.max_line_length is not None: 

368 maxlinelen = self.max_line_length 

369 parts.append(h.encode(linesep=self.linesep, maxlinelen=maxlinelen)) 

370 parts.append(self.linesep) 

371 return ''.join(parts) 

372 

373 

374compat32 = Compat32()