| Index: third_party/google-endpoints/future/backports/email/_policybase.py
|
| diff --git a/third_party/google-endpoints/future/backports/email/_policybase.py b/third_party/google-endpoints/future/backports/email/_policybase.py
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..c66aea90021a634044bbd54e918e96e276da3840
|
| --- /dev/null
|
| +++ b/third_party/google-endpoints/future/backports/email/_policybase.py
|
| @@ -0,0 +1,365 @@
|
| +"""Policy framework for the email package.
|
| +
|
| +Allows fine grained feature control of how the package parses and emits data.
|
| +"""
|
| +from __future__ import unicode_literals
|
| +from __future__ import print_function
|
| +from __future__ import division
|
| +from __future__ import absolute_import
|
| +from future.builtins import super
|
| +from future.builtins import str
|
| +from future.utils import with_metaclass
|
| +
|
| +import abc
|
| +from future.backports.email import header
|
| +from future.backports.email import charset as _charset
|
| +from future.backports.email.utils import _has_surrogates
|
| +
|
| +__all__ = [
|
| + 'Policy',
|
| + 'Compat32',
|
| + 'compat32',
|
| + ]
|
| +
|
| +
|
| +class _PolicyBase(object):
|
| +
|
| + """Policy Object basic framework.
|
| +
|
| + This class is useless unless subclassed. A subclass should define
|
| + class attributes with defaults for any values that are to be
|
| + managed by the Policy object. The constructor will then allow
|
| + non-default values to be set for these attributes at instance
|
| + creation time. The instance will be callable, taking these same
|
| + attributes keyword arguments, and returning a new instance
|
| + identical to the called instance except for those values changed
|
| + by the keyword arguments. Instances may be added, yielding new
|
| + instances with any non-default values from the right hand
|
| + operand overriding those in the left hand operand. That is,
|
| +
|
| + A + B == A(<non-default values of B>)
|
| +
|
| + The repr of an instance can be used to reconstruct the object
|
| + if and only if the repr of the values can be used to reconstruct
|
| + those values.
|
| +
|
| + """
|
| +
|
| + def __init__(self, **kw):
|
| + """Create new Policy, possibly overriding some defaults.
|
| +
|
| + See class docstring for a list of overridable attributes.
|
| +
|
| + """
|
| + for name, value in kw.items():
|
| + if hasattr(self, name):
|
| + super(_PolicyBase,self).__setattr__(name, value)
|
| + else:
|
| + raise TypeError(
|
| + "{!r} is an invalid keyword argument for {}".format(
|
| + name, self.__class__.__name__))
|
| +
|
| + def __repr__(self):
|
| + args = [ "{}={!r}".format(name, value)
|
| + for name, value in self.__dict__.items() ]
|
| + return "{}({})".format(self.__class__.__name__, ', '.join(args))
|
| +
|
| + def clone(self, **kw):
|
| + """Return a new instance with specified attributes changed.
|
| +
|
| + The new instance has the same attribute values as the current object,
|
| + except for the changes passed in as keyword arguments.
|
| +
|
| + """
|
| + newpolicy = self.__class__.__new__(self.__class__)
|
| + for attr, value in self.__dict__.items():
|
| + object.__setattr__(newpolicy, attr, value)
|
| + for attr, value in kw.items():
|
| + if not hasattr(self, attr):
|
| + raise TypeError(
|
| + "{!r} is an invalid keyword argument for {}".format(
|
| + attr, self.__class__.__name__))
|
| + object.__setattr__(newpolicy, attr, value)
|
| + return newpolicy
|
| +
|
| + def __setattr__(self, name, value):
|
| + if hasattr(self, name):
|
| + msg = "{!r} object attribute {!r} is read-only"
|
| + else:
|
| + msg = "{!r} object has no attribute {!r}"
|
| + raise AttributeError(msg.format(self.__class__.__name__, name))
|
| +
|
| + def __add__(self, other):
|
| + """Non-default values from right operand override those from left.
|
| +
|
| + The object returned is a new instance of the subclass.
|
| +
|
| + """
|
| + return self.clone(**other.__dict__)
|
| +
|
| +
|
| +def _append_doc(doc, added_doc):
|
| + doc = doc.rsplit('\n', 1)[0]
|
| + added_doc = added_doc.split('\n', 1)[1]
|
| + return doc + '\n' + added_doc
|
| +
|
| +def _extend_docstrings(cls):
|
| + if cls.__doc__ and cls.__doc__.startswith('+'):
|
| + cls.__doc__ = _append_doc(cls.__bases__[0].__doc__, cls.__doc__)
|
| + for name, attr in cls.__dict__.items():
|
| + if attr.__doc__ and attr.__doc__.startswith('+'):
|
| + for c in (c for base in cls.__bases__ for c in base.mro()):
|
| + doc = getattr(getattr(c, name), '__doc__')
|
| + if doc:
|
| + attr.__doc__ = _append_doc(doc, attr.__doc__)
|
| + break
|
| + return cls
|
| +
|
| +
|
| +class Policy(with_metaclass(abc.ABCMeta, _PolicyBase)):
|
| +
|
| + r"""Controls for how messages are interpreted and formatted.
|
| +
|
| + Most of the classes and many of the methods in the email package accept
|
| + Policy objects as parameters. A Policy object contains a set of values and
|
| + functions that control how input is interpreted and how output is rendered.
|
| + For example, the parameter 'raise_on_defect' controls whether or not an RFC
|
| + violation results in an error being raised or not, while 'max_line_length'
|
| + controls the maximum length of output lines when a Message is serialized.
|
| +
|
| + Any valid attribute may be overridden when a Policy is created by passing
|
| + it as a keyword argument to the constructor. Policy objects are immutable,
|
| + but a new Policy object can be created with only certain values changed by
|
| + calling the Policy instance with keyword arguments. Policy objects can
|
| + also be added, producing a new Policy object in which the non-default
|
| + attributes set in the right hand operand overwrite those specified in the
|
| + left operand.
|
| +
|
| + Settable attributes:
|
| +
|
| + raise_on_defect -- If true, then defects should be raised as errors.
|
| + Default: False.
|
| +
|
| + linesep -- string containing the value to use as separation
|
| + between output lines. Default '\n'.
|
| +
|
| + cte_type -- Type of allowed content transfer encodings
|
| +
|
| + 7bit -- ASCII only
|
| + 8bit -- Content-Transfer-Encoding: 8bit is allowed
|
| +
|
| + Default: 8bit. Also controls the disposition of
|
| + (RFC invalid) binary data in headers; see the
|
| + documentation of the binary_fold method.
|
| +
|
| + max_line_length -- maximum length of lines, excluding 'linesep',
|
| + during serialization. None or 0 means no line
|
| + wrapping is done. Default is 78.
|
| +
|
| + """
|
| +
|
| + raise_on_defect = False
|
| + linesep = '\n'
|
| + cte_type = '8bit'
|
| + max_line_length = 78
|
| +
|
| + def handle_defect(self, obj, defect):
|
| + """Based on policy, either raise defect or call register_defect.
|
| +
|
| + handle_defect(obj, defect)
|
| +
|
| + defect should be a Defect subclass, but in any case must be an
|
| + Exception subclass. obj is the object on which the defect should be
|
| + registered if it is not raised. If the raise_on_defect is True, the
|
| + defect is raised as an error, otherwise the object and the defect are
|
| + passed to register_defect.
|
| +
|
| + This method is intended to be called by parsers that discover defects.
|
| + The email package parsers always call it with Defect instances.
|
| +
|
| + """
|
| + if self.raise_on_defect:
|
| + raise defect
|
| + self.register_defect(obj, defect)
|
| +
|
| + def register_defect(self, obj, defect):
|
| + """Record 'defect' on 'obj'.
|
| +
|
| + Called by handle_defect if raise_on_defect is False. This method is
|
| + part of the Policy API so that Policy subclasses can implement custom
|
| + defect handling. The default implementation calls the append method of
|
| + the defects attribute of obj. The objects used by the email package by
|
| + default that get passed to this method will always have a defects
|
| + attribute with an append method.
|
| +
|
| + """
|
| + obj.defects.append(defect)
|
| +
|
| + def header_max_count(self, name):
|
| + """Return the maximum allowed number of headers named 'name'.
|
| +
|
| + Called when a header is added to a Message object. If the returned
|
| + value is not 0 or None, and there are already a number of headers with
|
| + the name 'name' equal to the value returned, a ValueError is raised.
|
| +
|
| + Because the default behavior of Message's __setitem__ is to append the
|
| + value to the list of headers, it is easy to create duplicate headers
|
| + without realizing it. This method allows certain headers to be limited
|
| + in the number of instances of that header that may be added to a
|
| + Message programmatically. (The limit is not observed by the parser,
|
| + which will faithfully produce as many headers as exist in the message
|
| + being parsed.)
|
| +
|
| + The default implementation returns None for all header names.
|
| + """
|
| + return None
|
| +
|
| + @abc.abstractmethod
|
| + def header_source_parse(self, sourcelines):
|
| + """Given a list of linesep terminated strings constituting the lines of
|
| + a single header, return the (name, value) tuple that should be stored
|
| + in the model. The input lines should retain their terminating linesep
|
| + characters. The lines passed in by the email package may contain
|
| + surrogateescaped binary data.
|
| + """
|
| + raise NotImplementedError
|
| +
|
| + @abc.abstractmethod
|
| + def header_store_parse(self, name, value):
|
| + """Given the header name and the value provided by the application
|
| + program, return the (name, value) that should be stored in the model.
|
| + """
|
| + raise NotImplementedError
|
| +
|
| + @abc.abstractmethod
|
| + def header_fetch_parse(self, name, value):
|
| + """Given the header name and the value from the model, return the value
|
| + to be returned to the application program that is requesting that
|
| + header. The value passed in by the email package may contain
|
| + surrogateescaped binary data if the lines were parsed by a BytesParser.
|
| + The returned value should not contain any surrogateescaped data.
|
| +
|
| + """
|
| + raise NotImplementedError
|
| +
|
| + @abc.abstractmethod
|
| + def fold(self, name, value):
|
| + """Given the header name and the value from the model, return a string
|
| + containing linesep characters that implement the folding of the header
|
| + according to the policy controls. The value passed in by the email
|
| + package may contain surrogateescaped binary data if the lines were
|
| + parsed by a BytesParser. The returned value should not contain any
|
| + surrogateescaped data.
|
| +
|
| + """
|
| + raise NotImplementedError
|
| +
|
| + @abc.abstractmethod
|
| + def fold_binary(self, name, value):
|
| + """Given the header name and the value from the model, return binary
|
| + data containing linesep characters that implement the folding of the
|
| + header according to the policy controls. The value passed in by the
|
| + email package may contain surrogateescaped binary data.
|
| +
|
| + """
|
| + raise NotImplementedError
|
| +
|
| +
|
| +@_extend_docstrings
|
| +class Compat32(Policy):
|
| +
|
| + """+
|
| + This particular policy is the backward compatibility Policy. It
|
| + replicates the behavior of the email package version 5.1.
|
| + """
|
| +
|
| + def _sanitize_header(self, name, value):
|
| + # If the header value contains surrogates, return a Header using
|
| + # the unknown-8bit charset to encode the bytes as encoded words.
|
| + if not isinstance(value, str):
|
| + # Assume it is already a header object
|
| + return value
|
| + if _has_surrogates(value):
|
| + return header.Header(value, charset=_charset.UNKNOWN8BIT,
|
| + header_name=name)
|
| + else:
|
| + return value
|
| +
|
| + def header_source_parse(self, sourcelines):
|
| + """+
|
| + The name is parsed as everything up to the ':' and returned unmodified.
|
| + The value is determined by stripping leading whitespace off the
|
| + remainder of the first line, joining all subsequent lines together, and
|
| + stripping any trailing carriage return or linefeed characters.
|
| +
|
| + """
|
| + name, value = sourcelines[0].split(':', 1)
|
| + value = value.lstrip(' \t') + ''.join(sourcelines[1:])
|
| + return (name, value.rstrip('\r\n'))
|
| +
|
| + def header_store_parse(self, name, value):
|
| + """+
|
| + The name and value are returned unmodified.
|
| + """
|
| + return (name, value)
|
| +
|
| + def header_fetch_parse(self, name, value):
|
| + """+
|
| + If the value contains binary data, it is converted into a Header object
|
| + using the unknown-8bit charset. Otherwise it is returned unmodified.
|
| + """
|
| + return self._sanitize_header(name, value)
|
| +
|
| + def fold(self, name, value):
|
| + """+
|
| + Headers are folded using the Header folding algorithm, which preserves
|
| + existing line breaks in the value, and wraps each resulting line to the
|
| + max_line_length. Non-ASCII binary data are CTE encoded using the
|
| + unknown-8bit charset.
|
| +
|
| + """
|
| + return self._fold(name, value, sanitize=True)
|
| +
|
| + def fold_binary(self, name, value):
|
| + """+
|
| + Headers are folded using the Header folding algorithm, which preserves
|
| + existing line breaks in the value, and wraps each resulting line to the
|
| + max_line_length. If cte_type is 7bit, non-ascii binary data is CTE
|
| + encoded using the unknown-8bit charset. Otherwise the original source
|
| + header is used, with its existing line breaks and/or binary data.
|
| +
|
| + """
|
| + folded = self._fold(name, value, sanitize=self.cte_type=='7bit')
|
| + return folded.encode('ascii', 'surrogateescape')
|
| +
|
| + def _fold(self, name, value, sanitize):
|
| + parts = []
|
| + parts.append('%s: ' % name)
|
| + if isinstance(value, str):
|
| + if _has_surrogates(value):
|
| + if sanitize:
|
| + h = header.Header(value,
|
| + charset=_charset.UNKNOWN8BIT,
|
| + header_name=name)
|
| + else:
|
| + # If we have raw 8bit data in a byte string, we have no idea
|
| + # what the encoding is. There is no safe way to split this
|
| + # string. If it's ascii-subset, then we could do a normal
|
| + # ascii split, but if it's multibyte then we could break the
|
| + # string. There's no way to know so the least harm seems to
|
| + # be to not split the string and risk it being too long.
|
| + parts.append(value)
|
| + h = None
|
| + else:
|
| + h = header.Header(value, header_name=name)
|
| + else:
|
| + # Assume it is a Header-like object.
|
| + h = value
|
| + if h is not None:
|
| + parts.append(h.encode(linesep=self.linesep,
|
| + maxlinelen=self.max_line_length))
|
| + parts.append(self.linesep)
|
| + return ''.join(parts)
|
| +
|
| +
|
| +compat32 = Compat32()
|
|
|