mirror of
https://github.com/python/cpython.git
synced 2025-08-04 17:08:35 +00:00
#20098: add mangle_from_ policy option.
This defaults to True in the compat32 policy for backward compatibility, but to False for all new policies. Patch by Milan Oberkirch, with a few tweaks.
This commit is contained in:
parent
224ef3ec3b
commit
fdb23c2fe5
7 changed files with 76 additions and 5 deletions
|
@ -187,6 +187,18 @@ added matters. To illustrate::
|
|||
:const:`False` (the default), defects will be passed to the
|
||||
:meth:`register_defect` method.
|
||||
|
||||
|
||||
|
||||
.. attribute:: mangle_from\_
|
||||
|
||||
If :const:`True`, lines starting with *"From "* in the body are
|
||||
escaped by putting a ``>`` in front of them. This parameter is used when
|
||||
the message is being serialized by a generator.
|
||||
Default: :const:`False`.
|
||||
|
||||
.. versionadded:: 3.5
|
||||
The *mangle_from_* parameter.
|
||||
|
||||
The following :class:`Policy` method is intended to be called by code using
|
||||
the email library to create policy instances with custom settings:
|
||||
|
||||
|
@ -319,6 +331,13 @@ added matters. To illustrate::
|
|||
:const:`compat32`, that is used as the default policy. Thus the default
|
||||
behavior of the email package is to maintain compatibility with Python 3.2.
|
||||
|
||||
The following attributes have values that are different from the
|
||||
:class:`Policy` default:
|
||||
|
||||
.. attribute:: mangle_from_
|
||||
|
||||
The default is ``True``.
|
||||
|
||||
The class provides the following concrete implementations of the
|
||||
abstract methods of :class:`Policy`:
|
||||
|
||||
|
@ -356,6 +375,14 @@ added matters. To illustrate::
|
|||
line breaks and any (RFC invalid) binary data it may contain.
|
||||
|
||||
|
||||
An instance of :class:`Compat32` is provided as a module constant:
|
||||
|
||||
.. data:: compat32
|
||||
|
||||
An instance of :class:`Compat32`, providing backward compatibility with the
|
||||
behavior of the email package in Python 3.2.
|
||||
|
||||
|
||||
.. note::
|
||||
|
||||
The documentation below describes new policies that are included in the
|
||||
|
|
|
@ -351,6 +351,12 @@ doctest
|
|||
email
|
||||
-----
|
||||
|
||||
* A new policy option :attr:`~email.policy.Policy.mangle_from_` controls
|
||||
whether or not lines that start with "From " in email bodies are prefixed with
|
||||
a '>' character by generators. The default is ``True`` for
|
||||
:attr:`~email.policy.compat32` and ``False`` for all other policies.
|
||||
(Contributed by Milan Oberkirch in :issue:`20098`.)
|
||||
|
||||
* A new method :meth:`~email.message.Message.get_content_disposition` provides
|
||||
easy access to a canonical value for the :mailheader:`Content-Disposition`
|
||||
header (``None`` if there is no such header). (Contributed by Abhilash Raj
|
||||
|
|
|
@ -149,12 +149,18 @@ class Policy(_PolicyBase, metaclass=abc.ABCMeta):
|
|||
during serialization. None or 0 means no line
|
||||
wrapping is done. Default is 78.
|
||||
|
||||
mangle_from_ -- a flag that, when True escapes From_ lines in the
|
||||
body of the message by putting a `>' in front of
|
||||
them. This is used when the message is being
|
||||
serialized by a generator. Default: True.
|
||||
|
||||
"""
|
||||
|
||||
raise_on_defect = False
|
||||
linesep = '\n'
|
||||
cte_type = '8bit'
|
||||
max_line_length = 78
|
||||
mangle_from_ = False
|
||||
|
||||
def handle_defect(self, obj, defect):
|
||||
"""Based on policy, either raise defect or call register_defect.
|
||||
|
@ -266,6 +272,8 @@ class Compat32(Policy):
|
|||
replicates the behavior of the email package version 5.1.
|
||||
"""
|
||||
|
||||
mangle_from_ = True
|
||||
|
||||
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.
|
||||
|
|
|
@ -32,16 +32,16 @@ class Generator:
|
|||
# Public interface
|
||||
#
|
||||
|
||||
def __init__(self, outfp, mangle_from_=True, maxheaderlen=None, *,
|
||||
def __init__(self, outfp, mangle_from_=None, maxheaderlen=None, *,
|
||||
policy=None):
|
||||
"""Create the generator for message flattening.
|
||||
|
||||
outfp is the output file-like object for writing the message to. It
|
||||
must have a write() method.
|
||||
|
||||
Optional mangle_from_ is a flag that, when True (the default), escapes
|
||||
From_ lines in the body of the message by putting a `>' in front of
|
||||
them.
|
||||
Optional mangle_from_ is a flag that, when True (the default if policy
|
||||
is not set), escapes From_ lines in the body of the message by putting
|
||||
a `>' in front of them.
|
||||
|
||||
Optional maxheaderlen specifies the longest length for a non-continued
|
||||
header. When a header line is longer (in characters, with tabs
|
||||
|
@ -56,6 +56,9 @@ class Generator:
|
|||
flatten method is used.
|
||||
|
||||
"""
|
||||
|
||||
if mangle_from_ is None:
|
||||
mangle_from_ = True if policy is None else policy.mangle_from_
|
||||
self._fp = outfp
|
||||
self._mangle_from_ = mangle_from_
|
||||
self.maxheaderlen = maxheaderlen
|
||||
|
@ -449,7 +452,7 @@ class DecodedGenerator(Generator):
|
|||
Like the Generator base class, except that non-text parts are substituted
|
||||
with a format string representing the part.
|
||||
"""
|
||||
def __init__(self, outfp, mangle_from_=True, maxheaderlen=78, fmt=None):
|
||||
def __init__(self, outfp, mangle_from_=None, maxheaderlen=78, fmt=None):
|
||||
"""Like Generator.__init__() except that an additional optional
|
||||
argument is allowed.
|
||||
|
||||
|
|
|
@ -140,6 +140,28 @@ class TestGeneratorBase:
|
|||
g.flatten(msg, linesep='\n')
|
||||
self.assertEqual(s.getvalue(), self.typ(expected))
|
||||
|
||||
def test_set_mangle_from_via_policy(self):
|
||||
source = textwrap.dedent("""\
|
||||
Subject: test that
|
||||
from is mangeld in the body!
|
||||
|
||||
From time to time I write a rhyme.
|
||||
""")
|
||||
variants = (
|
||||
(None, True),
|
||||
(policy.compat32, True),
|
||||
(policy.default, False),
|
||||
(policy.default.clone(mangle_from_=True), True),
|
||||
)
|
||||
for p, mangle in variants:
|
||||
expected = source.replace('From ', '>From ') if mangle else source
|
||||
with self.subTest(policy=p, mangle_from_=mangle):
|
||||
msg = self.msgmaker(self.typ(source))
|
||||
s = self.ioclass()
|
||||
g = self.genclass(s, policy=p)
|
||||
g.flatten(msg)
|
||||
self.assertEqual(s.getvalue(), self.typ(expected))
|
||||
|
||||
|
||||
class TestGenerator(TestGeneratorBase, TestEmailBase):
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ class PolicyAPITests(unittest.TestCase):
|
|||
'linesep': '\n',
|
||||
'cte_type': '8bit',
|
||||
'raise_on_defect': False,
|
||||
'mangle_from_': True,
|
||||
}
|
||||
# These default values are the ones set on email.policy.default.
|
||||
# If any of these defaults change, the docs must be updated.
|
||||
|
@ -32,6 +33,7 @@ class PolicyAPITests(unittest.TestCase):
|
|||
'header_factory': email.policy.EmailPolicy.header_factory,
|
||||
'refold_source': 'long',
|
||||
'content_manager': email.policy.EmailPolicy.content_manager,
|
||||
'mangle_from_': False,
|
||||
})
|
||||
|
||||
# For each policy under test, we give here what we expect the defaults to
|
||||
|
|
|
@ -47,6 +47,9 @@ Core and Builtins
|
|||
Library
|
||||
-------
|
||||
|
||||
- Issue #20098: New mangle_from_ policy option for email, default True
|
||||
for compat32, but False for all other policies.
|
||||
|
||||
- Issue #24211: The email library now supports RFC 6532: it can generate
|
||||
headers using utf-8 instead of encoded words.
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue