X Tutup
Skip to content

Commit fdb23c2

Browse files
committed
python#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.
1 parent 224ef3e commit fdb23c2

File tree

7 files changed

+76
-5
lines changed

7 files changed

+76
-5
lines changed

Doc/library/email.policy.rst

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,18 @@ added matters. To illustrate::
187187
:const:`False` (the default), defects will be passed to the
188188
:meth:`register_defect` method.
189189

190+
191+
192+
.. attribute:: mangle_from\_
193+
194+
If :const:`True`, lines starting with *"From "* in the body are
195+
escaped by putting a ``>`` in front of them. This parameter is used when
196+
the message is being serialized by a generator.
197+
Default: :const:`False`.
198+
199+
.. versionadded:: 3.5
200+
The *mangle_from_* parameter.
201+
190202
The following :class:`Policy` method is intended to be called by code using
191203
the email library to create policy instances with custom settings:
192204

@@ -319,6 +331,13 @@ added matters. To illustrate::
319331
:const:`compat32`, that is used as the default policy. Thus the default
320332
behavior of the email package is to maintain compatibility with Python 3.2.
321333

334+
The following attributes have values that are different from the
335+
:class:`Policy` default:
336+
337+
.. attribute:: mangle_from_
338+
339+
The default is ``True``.
340+
322341
The class provides the following concrete implementations of the
323342
abstract methods of :class:`Policy`:
324343

@@ -356,6 +375,14 @@ added matters. To illustrate::
356375
line breaks and any (RFC invalid) binary data it may contain.
357376

358377

378+
An instance of :class:`Compat32` is provided as a module constant:
379+
380+
.. data:: compat32
381+
382+
An instance of :class:`Compat32`, providing backward compatibility with the
383+
behavior of the email package in Python 3.2.
384+
385+
359386
.. note::
360387

361388
The documentation below describes new policies that are included in the

Doc/whatsnew/3.5.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,12 @@ doctest
351351
email
352352
-----
353353

354+
* A new policy option :attr:`~email.policy.Policy.mangle_from_` controls
355+
whether or not lines that start with "From " in email bodies are prefixed with
356+
a '>' character by generators. The default is ``True`` for
357+
:attr:`~email.policy.compat32` and ``False`` for all other policies.
358+
(Contributed by Milan Oberkirch in :issue:`20098`.)
359+
354360
* A new method :meth:`~email.message.Message.get_content_disposition` provides
355361
easy access to a canonical value for the :mailheader:`Content-Disposition`
356362
header (``None`` if there is no such header). (Contributed by Abhilash Raj

Lib/email/_policybase.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,12 +149,18 @@ class Policy(_PolicyBase, metaclass=abc.ABCMeta):
149149
during serialization. None or 0 means no line
150150
wrapping is done. Default is 78.
151151
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+
152157
"""
153158

154159
raise_on_defect = False
155160
linesep = '\n'
156161
cte_type = '8bit'
157162
max_line_length = 78
163+
mangle_from_ = False
158164

159165
def handle_defect(self, obj, defect):
160166
"""Based on policy, either raise defect or call register_defect.
@@ -266,6 +272,8 @@ class Compat32(Policy):
266272
replicates the behavior of the email package version 5.1.
267273
"""
268274

275+
mangle_from_ = True
276+
269277
def _sanitize_header(self, name, value):
270278
# If the header value contains surrogates, return a Header using
271279
# the unknown-8bit charset to encode the bytes as encoded words.

Lib/email/generator.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,16 +32,16 @@ class Generator:
3232
# Public interface
3333
#
3434

35-
def __init__(self, outfp, mangle_from_=True, maxheaderlen=None, *,
35+
def __init__(self, outfp, mangle_from_=None, maxheaderlen=None, *,
3636
policy=None):
3737
"""Create the generator for message flattening.
3838
3939
outfp is the output file-like object for writing the message to. It
4040
must have a write() method.
4141
42-
Optional mangle_from_ is a flag that, when True (the default), escapes
43-
From_ lines in the body of the message by putting a `>' in front of
44-
them.
42+
Optional mangle_from_ is a flag that, when True (the default if policy
43+
is not set), escapes From_ lines in the body of the message by putting
44+
a `>' in front of them.
4545
4646
Optional maxheaderlen specifies the longest length for a non-continued
4747
header. When a header line is longer (in characters, with tabs
@@ -56,6 +56,9 @@ def __init__(self, outfp, mangle_from_=True, maxheaderlen=None, *,
5656
flatten method is used.
5757
5858
"""
59+
60+
if mangle_from_ is None:
61+
mangle_from_ = True if policy is None else policy.mangle_from_
5962
self._fp = outfp
6063
self._mangle_from_ = mangle_from_
6164
self.maxheaderlen = maxheaderlen
@@ -449,7 +452,7 @@ class DecodedGenerator(Generator):
449452
Like the Generator base class, except that non-text parts are substituted
450453
with a format string representing the part.
451454
"""
452-
def __init__(self, outfp, mangle_from_=True, maxheaderlen=78, fmt=None):
455+
def __init__(self, outfp, mangle_from_=None, maxheaderlen=78, fmt=None):
453456
"""Like Generator.__init__() except that an additional optional
454457
argument is allowed.
455458

Lib/test/test_email/test_generator.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,28 @@ def test_flatten_linesep_overrides_policy(self):
140140
g.flatten(msg, linesep='\n')
141141
self.assertEqual(s.getvalue(), self.typ(expected))
142142

143+
def test_set_mangle_from_via_policy(self):
144+
source = textwrap.dedent("""\
145+
Subject: test that
146+
from is mangeld in the body!
147+
148+
From time to time I write a rhyme.
149+
""")
150+
variants = (
151+
(None, True),
152+
(policy.compat32, True),
153+
(policy.default, False),
154+
(policy.default.clone(mangle_from_=True), True),
155+
)
156+
for p, mangle in variants:
157+
expected = source.replace('From ', '>From ') if mangle else source
158+
with self.subTest(policy=p, mangle_from_=mangle):
159+
msg = self.msgmaker(self.typ(source))
160+
s = self.ioclass()
161+
g = self.genclass(s, policy=p)
162+
g.flatten(msg)
163+
self.assertEqual(s.getvalue(), self.typ(expected))
164+
143165

144166
class TestGenerator(TestGeneratorBase, TestEmailBase):
145167

Lib/test/test_email/test_policy.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ class PolicyAPITests(unittest.TestCase):
2222
'linesep': '\n',
2323
'cte_type': '8bit',
2424
'raise_on_defect': False,
25+
'mangle_from_': True,
2526
}
2627
# These default values are the ones set on email.policy.default.
2728
# If any of these defaults change, the docs must be updated.
@@ -32,6 +33,7 @@ class PolicyAPITests(unittest.TestCase):
3233
'header_factory': email.policy.EmailPolicy.header_factory,
3334
'refold_source': 'long',
3435
'content_manager': email.policy.EmailPolicy.content_manager,
36+
'mangle_from_': False,
3537
})
3638

3739
# For each policy under test, we give here what we expect the defaults to

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ Core and Builtins
4747
Library
4848
-------
4949

50+
- Issue #20098: New mangle_from_ policy option for email, default True
51+
for compat32, but False for all other policies.
52+
5053
- Issue #24211: The email library now supports RFC 6532: it can generate
5154
headers using utf-8 instead of encoded words.
5255

0 commit comments

Comments
 (0)
X Tutup