| OLD | NEW |
| (Empty) | |
| 1 """Policy framework for the email package. |
| 2 |
| 3 Allows fine grained feature control of how the package parses and emits data. |
| 4 """ |
| 5 |
| 6 import abc |
| 7 from email import header |
| 8 from email import charset as _charset |
| 9 from email.utils import _has_surrogates |
| 10 |
| 11 __all__ = [ |
| 12 'Policy', |
| 13 'Compat32', |
| 14 'compat32', |
| 15 ] |
| 16 |
| 17 |
| 18 class _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 for attr, value in self.__dict__.items(): |
| 68 if attr not in kw: |
| 69 kw[attr] = value |
| 70 return self.__class__(**kw) |
| 71 |
| 72 def __setattr__(self, name, value): |
| 73 if hasattr(self, name): |
| 74 msg = "{!r} object attribute {!r} is read-only" |
| 75 else: |
| 76 msg = "{!r} object has no attribute {!r}" |
| 77 raise AttributeError(msg.format(self.__class__.__name__, name)) |
| 78 |
| 79 def __add__(self, other): |
| 80 """Non-default values from right operand override those from left. |
| 81 |
| 82 The object returned is a new instance of the subclass. |
| 83 |
| 84 """ |
| 85 return self.clone(**other.__dict__) |
| 86 |
| 87 |
| 88 # Conceptually this isn't a subclass of ABCMeta, but since we want Policy to |
| 89 # use ABCMeta as a metaclass *and* we want it to use this one as well, we have |
| 90 # to make this one a subclas of ABCMeta. |
| 91 class _DocstringExtenderMetaclass(abc.ABCMeta): |
| 92 |
| 93 def __new__(meta, classname, bases, classdict): |
| 94 if classdict.get('__doc__') and classdict['__doc__'].startswith('+'): |
| 95 classdict['__doc__'] = meta._append_doc(bases[0].__doc__, |
| 96 classdict['__doc__']) |
| 97 for name, attr in classdict.items(): |
| 98 if attr.__doc__ and attr.__doc__.startswith('+'): |
| 99 for cls in (cls for base in bases for cls in base.mro()): |
| 100 doc = getattr(getattr(cls, name), '__doc__') |
| 101 if doc: |
| 102 attr.__doc__ = meta._append_doc(doc, attr.__doc__) |
| 103 break |
| 104 return super().__new__(meta, classname, bases, classdict) |
| 105 |
| 106 @staticmethod |
| 107 def _append_doc(doc, added_doc): |
| 108 added_doc = added_doc.split('\n', 1)[1] |
| 109 return doc + '\n' + added_doc |
| 110 |
| 111 |
| 112 class Policy(_PolicyBase, metaclass=_DocstringExtenderMetaclass): |
| 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 """ |
| 153 |
| 154 raise_on_defect = False |
| 155 linesep = '\n' |
| 156 cte_type = '8bit' |
| 157 max_line_length = 78 |
| 158 |
| 159 def handle_defect(self, obj, defect): |
| 160 """Based on policy, either raise defect or call register_defect. |
| 161 |
| 162 handle_defect(obj, defect) |
| 163 |
| 164 defect should be a Defect subclass, but in any case must be an |
| 165 Exception subclass. obj is the object on which the defect should be |
| 166 registered if it is not raised. If the raise_on_defect is True, the |
| 167 defect is raised as an error, otherwise the object and the defect are |
| 168 passed to register_defect. |
| 169 |
| 170 This method is intended to be called by parsers that discover defects. |
| 171 The email package parsers always call it with Defect instances. |
| 172 |
| 173 """ |
| 174 if self.raise_on_defect: |
| 175 raise defect |
| 176 self.register_defect(obj, defect) |
| 177 |
| 178 def register_defect(self, obj, defect): |
| 179 """Record 'defect' on 'obj'. |
| 180 |
| 181 Called by handle_defect if raise_on_defect is False. This method is |
| 182 part of the Policy API so that Policy subclasses can implement custom |
| 183 defect handling. The default implementation calls the append method of |
| 184 the defects attribute of obj. The objects used by the email package by |
| 185 default that get passed to this method will always have a defects |
| 186 attribute with an append method. |
| 187 |
| 188 """ |
| 189 obj.defects.append(defect) |
| 190 |
| 191 @abc.abstractmethod |
| 192 def header_source_parse(self, sourcelines): |
| 193 """Given a list of linesep terminated strings constituting the lines of |
| 194 a single header, return the (name, value) tuple that should be stored |
| 195 in the model. The input lines should retain their terminating linesep |
| 196 characters. The lines passed in by the email package may contain |
| 197 surrogateescaped binary data. |
| 198 """ |
| 199 raise NotImplementedError |
| 200 |
| 201 @abc.abstractmethod |
| 202 def header_store_parse(self, name, value): |
| 203 """Given the header name and the value provided by the application |
| 204 program, return the (name, value) that should be stored in the model. |
| 205 """ |
| 206 raise NotImplementedError |
| 207 |
| 208 @abc.abstractmethod |
| 209 def header_fetch_parse(self, name, value): |
| 210 """Given the header name and the value from the model, return the value |
| 211 to be returned to the application program that is requesting that |
| 212 header. The value passed in by the email package may contain |
| 213 surrogateescaped binary data if the lines were parsed by a BytesParser. |
| 214 The returned value should not contain any surrogateescaped data. |
| 215 |
| 216 """ |
| 217 raise NotImplementedError |
| 218 |
| 219 @abc.abstractmethod |
| 220 def fold(self, name, value): |
| 221 """Given the header name and the value from the model, return a string |
| 222 containing linesep characters that implement the folding of the header |
| 223 according to the policy controls. The value passed in by the email |
| 224 package may contain surrogateescaped binary data if the lines were |
| 225 parsed by a BytesParser. The returned value should not contain any |
| 226 surrogateescaped data. |
| 227 |
| 228 """ |
| 229 raise NotImplementedError |
| 230 |
| 231 @abc.abstractmethod |
| 232 def fold_binary(self, name, value): |
| 233 """Given the header name and the value from the model, return binary |
| 234 data containing linesep characters that implement the folding of the |
| 235 header according to the policy controls. The value passed in by the |
| 236 email package may contain surrogateescaped binary data. |
| 237 |
| 238 """ |
| 239 raise NotImplementedError |
| 240 |
| 241 |
| 242 class Compat32(Policy): |
| 243 |
| 244 """+ |
| 245 This particular policy is the backward compatibility Policy. It |
| 246 replicates the behavior of the email package version 5.1. |
| 247 """ |
| 248 |
| 249 def _sanitize_header(self, name, value): |
| 250 # If the header value contains surrogates, return a Header using |
| 251 # the unknown-8bit charset to encode the bytes as encoded words. |
| 252 if not isinstance(value, str): |
| 253 # Assume it is already a header object |
| 254 return value |
| 255 if _has_surrogates(value): |
| 256 return header.Header(value, charset=_charset.UNKNOWN8BIT, |
| 257 header_name=name) |
| 258 else: |
| 259 return value |
| 260 |
| 261 def header_source_parse(self, sourcelines): |
| 262 """+ |
| 263 The name is parsed as everything up to the ':' and returned unmodified. |
| 264 The value is determined by stripping leading whitespace off the |
| 265 remainder of the first line, joining all subsequent lines together, and |
| 266 stripping any trailing carriage return or linefeed characters. |
| 267 |
| 268 """ |
| 269 name, value = sourcelines[0].split(':', 1) |
| 270 value = value.lstrip(' \t') + ''.join(sourcelines[1:]) |
| 271 return (name, value.rstrip('\r\n')) |
| 272 |
| 273 def header_store_parse(self, name, value): |
| 274 """+ |
| 275 The name and value are returned unmodified. |
| 276 """ |
| 277 return (name, value) |
| 278 |
| 279 def header_fetch_parse(self, name, value): |
| 280 """+ |
| 281 If the value contains binary data, it is converted into a Header object |
| 282 using the unknown-8bit charset. Otherwise it is returned unmodified. |
| 283 """ |
| 284 return self._sanitize_header(name, value) |
| 285 |
| 286 def fold(self, name, value): |
| 287 """+ |
| 288 Headers are folded using the Header folding algorithm, which preserves |
| 289 existing line breaks in the value, and wraps each resulting line to the |
| 290 max_line_length. Non-ASCII binary data are CTE encoded using the |
| 291 unknown-8bit charset. |
| 292 |
| 293 """ |
| 294 return self._fold(name, value, sanitize=True) |
| 295 |
| 296 def fold_binary(self, name, value): |
| 297 """+ |
| 298 Headers are folded using the Header folding algorithm, which preserves |
| 299 existing line breaks in the value, and wraps each resulting line to the |
| 300 max_line_length. If cte_type is 7bit, non-ascii binary data is CTE |
| 301 encoded using the unknown-8bit charset. Otherwise the original source |
| 302 header is used, with its existing line breaks and/or binary data. |
| 303 |
| 304 """ |
| 305 folded = self._fold(name, value, sanitize=self.cte_type=='7bit') |
| 306 return folded.encode('ascii', 'surrogateescape') |
| 307 |
| 308 def _fold(self, name, value, sanitize): |
| 309 parts = [] |
| 310 parts.append('%s: ' % name) |
| 311 if isinstance(value, str): |
| 312 if _has_surrogates(value): |
| 313 if sanitize: |
| 314 h = header.Header(value, |
| 315 charset=_charset.UNKNOWN8BIT, |
| 316 header_name=name) |
| 317 else: |
| 318 # If we have raw 8bit data in a byte string, we have no idea |
| 319 # what the encoding is. There is no safe way to split this |
| 320 # string. If it's ascii-subset, then we could do a normal |
| 321 # ascii split, but if it's multibyte then we could break the |
| 322 # string. There's no way to know so the least harm seems to |
| 323 # be to not split the string and risk it being too long. |
| 324 parts.append(value) |
| 325 h = None |
| 326 else: |
| 327 h = header.Header(value, header_name=name) |
| 328 else: |
| 329 # Assume it is a Header-like object. |
| 330 h = value |
| 331 if h is not None: |
| 332 parts.append(h.encode(linesep=self.linesep, |
| 333 maxlinelen=self.max_line_length)) |
| 334 parts.append(self.linesep) |
| 335 return ''.join(parts) |
| 336 |
| 337 |
| 338 compat32 = Compat32() |
| OLD | NEW |