cpython: 53287858e71f (original) (raw)
Mercurial > cpython
changeset 85076:53287858e71f
#18600: add policy to add_string, and as_bytes and __bytes__ methods. This was triggered by wanting to make the doctest in email.policy.rst pass; as_bytes and __bytes__ are clearly useful now that we have BytesGenerator. Also updated the Message docs to document the policy keyword that was added in 3.3. [#18600]
R David Murray rdmurray@bitdance.com | |
---|---|
date | Fri, 09 Aug 2013 16:15:28 -0400 |
parents | a206f952668e |
children | b9a5b7e3b32f |
files | Doc/library/email.message.rst Doc/library/email.policy.rst Doc/whatsnew/3.4.rst Lib/email/message.py Lib/test/test_email/test_email.py Misc/NEWS |
diffstat | 6 files changed, 160 insertions(+), 21 deletions(-)[+] [-] Doc/library/email.message.rst 78 Doc/library/email.policy.rst 3 Doc/whatsnew/3.4.rst 20 Lib/email/message.py 44 Lib/test/test_email/test_email.py 33 Misc/NEWS 3 |
line wrap: on
line diff
--- a/Doc/library/email.message.rst
+++ b/Doc/library/email.message.rst
@@ -31,19 +31,32 @@ parameters, and for recursively walking
Here are the methods of the :class:Message
class:
-.. class:: Message()
+.. class:: Message(policy=compat32)
- The policy argument determiens the :mod:
~email.policy
that will be used - to update the message model. The default value, :class:`compat32
- <email.policy.Compat32>` maintains backward compatibility with the
- Python 3.2 version of the email package. For more information see the
- :mod:
~email.policy
documentation. + - .. versionchanged:: 3.3 The policy keyword argument was added.
- .. method:: as_string(unixfrom=False, maxheaderlen=0, policy=None) Return the entire message flattened as a string. When optional unixfrom
is ``True``, the envelope header is included in the returned string.[](#l1.24)
*unixfrom* defaults to ``False``. Flattening the message may trigger[](#l1.25)
changes to the :class:`Message` if defaults need to be filled in to[](#l1.26)
complete the transformation to a string (for example, MIME boundaries may[](#l1.27)
be generated or modified).[](#l1.28)
is true, the envelope header is included in the returned string.[](#l1.29)
*unixfrom* defaults to ``False``. For backward compabitility reasons,[](#l1.30)
*maxheaderlen* defaults to ``0``, so if you want a different value you[](#l1.31)
must override it explicitly (the value specified for *max_line_length* in[](#l1.32)
the policy will be ignored by this method). The *policy* argument may be[](#l1.33)
used to override the default policy obtained from the message instance.[](#l1.34)
This can be used to control some of the formatting produced by the[](#l1.35)
method, since the specified *policy* will be passed to the ``Generator``.[](#l1.36)
Flattening the message may trigger changes to the :class:`Message` if[](#l1.38)
defaults need to be filled in to complete the transformation to a string[](#l1.39)
(for example, MIME boundaries may be generated or modified).[](#l1.40)
Note that this method is provided as a convenience and may not always format the message the way you want. For example, by default it does @@ -59,10 +72,57 @@ Here are the methods of the :class:`Mess g.flatten(msg) text = fp.getvalue()
If the message object contains binary data that is not encoded according[](#l1.48)
to RFC standards, the non-compliant data will be replaced by unicode[](#l1.49)
"unknown character" code points. (See also :meth:`.as_bytes` and[](#l1.50)
:class:`~email.generator.BytesGenerator`.)[](#l1.51)
.. versionchanged:: 3.4 the *policy* keyword argument was added.[](#l1.53)
Equivalent to ``as_string(unixfrom=True)``.[](#l1.58)
Equivalent to :meth:`.as_string()`. Allows ``str(msg)`` to produce a[](#l1.59)
string containing the formatted message.[](#l1.60)
- .. method:: as_bytes(unixfrom=False, policy=None) +
Return the entire message flattened as a bytes object. When optional[](#l1.65)
*unixfrom* is true, the envelope header is included in the returned[](#l1.66)
string. *unixfrom* defaults to ``False``. The *policy* argument may be[](#l1.67)
used to override the default policy obtained from the message instance.[](#l1.68)
This can be used to control some of the formatting produced by the[](#l1.69)
method, since the specified *policy* will be passed to the[](#l1.70)
``BytesGenerator``.[](#l1.71)
Flattening the message may trigger changes to the :class:`Message` if[](#l1.73)
defaults need to be filled in to complete the transformation to a string[](#l1.74)
(for example, MIME boundaries may be generated or modified).[](#l1.75)
Note that this method is provided as a convenience and may not always[](#l1.77)
format the message the way you want. For example, by default it does[](#l1.78)
not do the mangling of lines that begin with ``From`` that is[](#l1.79)
required by the unix mbox format. For more flexibility, instantiate a[](#l1.80)
:class:`~email.generator.BytesGenerator` instance and use its[](#l1.81)
:meth:`flatten` method directly. For example::[](#l1.82)
from io import BytesIO[](#l1.84)
from email.generator import BytesGenerator[](#l1.85)
fp = BytesIO()[](#l1.86)
g = BytesGenerator(fp, mangle_from_=True, maxheaderlen=60)[](#l1.87)
g.flatten(msg)[](#l1.88)
text = fp.getvalue()[](#l1.89)
.. versionadded:: 3.4[](#l1.91)
- .. method:: bytes() +
Equivalent to :meth:`.as_bytes()`. Allows ``bytes(msg)`` to produce a[](#l1.96)
bytes object containing the formatted message.[](#l1.97)
.. versionadded:: 3.4[](#l1.99)
--- a/Doc/library/email.policy.rst +++ b/Doc/library/email.policy.rst @@ -105,7 +105,8 @@ separators for the platform on which it >>> import os >>> with open('converted.txt', 'wb') as f:
Policy objects can also be combined using the addition operator, producing a policy object whose settings are a combination of the non-default values of the
--- a/Doc/whatsnew/3.4.rst
+++ b/Doc/whatsnew/3.4.rst
@@ -195,6 +195,26 @@ The :meth:~aifc.getparams
method now r
plain tuple. (Contributed by Claudiu Popa in :issue:17818
.)
+email
+-----
+
+:meth:~email.message.Message.as_string
now accepts a policy argument to
+override the default policy of the message when generating a string
+representation of it. This means that as_string
can now be used in more
+circumstances, instead of having to create and use a :mod:~email.generator
in
+order to pass formatting parameters to its flatten
method.
+
+New method :meth:~email.message.Message.as_bytes
added to produce a bytes
+representation of the message in a fashion similar to how as_string
+produces a string representation. It does not accept the maxheaderlen
+argument, but does accept the unixfrom and policy arguments. The
+:class:~email.message.Message
:meth:~email.message.Message.__bytes__
method
+calls it, meaning that bytes(mymsg)
will now produce the intuitive
+result: a bytes object containing the fully formatted message.
+
+(Contributed by R. David Murray in :issue:18600
.)
+
+
functools
---------
--- a/Lib/email/message.py +++ b/Lib/email/message.py @@ -132,22 +132,50 @@ class Message: def str(self): """Return the entire formatted message as a string.
This includes the headers, body, and envelope header.[](#l4.7) """[](#l4.8) return self.as_string()[](#l4.9)
- def as_string(self, unixfrom=False, maxheaderlen=0, policy=None): """Return the entire formatted message as a string.
Optional `unixfrom' when True, means include the Unix From_ envelope[](#l4.14)
header.[](#l4.15)
This is a convenience method and may not generate the message exactly[](#l4.17)
as you intend. For more flexibility, use the flatten() method of a[](#l4.18)
Generator instance.[](#l4.19)
Optional 'unixfrom', when true, means include the Unix From_ envelope[](#l4.20)
header. For backward compatibility reasons, if maxheaderlen is[](#l4.21)
not specified it defaults to 0, so you must override it explicitly[](#l4.22)
if you want a different maxheaderlen. 'policy' is passed to the[](#l4.23)
Generator instance used to serialize the mesasge; if it is not[](#l4.24)
specified the policy associated with the message instance is used.[](#l4.25)
If the message object contains binary data that is not encoded[](#l4.27)
according to RFC standards, the non-compliant data will be replaced by[](#l4.28)
unicode "unknown character" code points.[](#l4.29) """[](#l4.30) from email.generator import Generator[](#l4.31)
policy = self.policy if policy is None else policy[](#l4.32) fp = StringIO()[](#l4.33)
g = Generator(fp, mangle_from_=False, maxheaderlen=maxheaderlen)[](#l4.34)
g = Generator(fp,[](#l4.35)
mangle_from_=False,[](#l4.36)
maxheaderlen=maxheaderlen,[](#l4.37)
policy=policy)[](#l4.38)
g.flatten(self, unixfrom=unixfrom)[](#l4.39)
return fp.getvalue()[](#l4.40)
- def bytes(self):
"""Return the entire formatted message as a bytes object.[](#l4.43)
"""[](#l4.44)
return self.as_bytes()[](#l4.45)
- def as_bytes(self, unixfrom=False, policy=None):
"""Return the entire formatted message as a bytes object.[](#l4.48)
Optional 'unixfrom', when true, means include the Unix From_ envelope[](#l4.50)
header. 'policy' is passed to the BytesGenerator instance used to[](#l4.51)
serialize the message; if not specified the policy associated with[](#l4.52)
the message instance is used.[](#l4.53)
"""[](#l4.54)
from email.generator import BytesGenerator[](#l4.55)
policy = self.policy if policy is None else policy[](#l4.56)
fp = BytesIO()[](#l4.57)
g = BytesGenerator(fp, mangle_from_=False, policy=policy)[](#l4.58) g.flatten(self, unixfrom=unixfrom)[](#l4.59) return fp.getvalue()[](#l4.60)
--- a/Lib/test/test_email/test_email.py +++ b/Lib/test/test_email/test_email.py @@ -249,15 +249,42 @@ class TestMessageAPI(TestEmailBase): self.assertTrue('TO' in msg) def test_as_string(self):
eq = self.ndiffAssertEqual[](#l5.7) msg = self._msgobj('msg_01.txt')[](#l5.8) with openfile('msg_01.txt') as fp:[](#l5.9) text = fp.read()[](#l5.10)
eq(text, str(msg))[](#l5.11)
self.assertEqual(text, str(msg))[](#l5.12) fullrepr = msg.as_string(unixfrom=True)[](#l5.13) lines = fullrepr.split('\n')[](#l5.14) self.assertTrue(lines[0].startswith('From '))[](#l5.15)
eq(text, NL.join(lines[1:]))[](#l5.16)
self.assertEqual(text, NL.join(lines[1:]))[](#l5.17)
- def test_as_string_policy(self):
msg = self._msgobj('msg_01.txt')[](#l5.20)
newpolicy = msg.policy.clone(linesep='\r\n')[](#l5.21)
fullrepr = msg.as_string(policy=newpolicy)[](#l5.22)
s = StringIO()[](#l5.23)
g = Generator(s, policy=newpolicy)[](#l5.24)
g.flatten(msg)[](#l5.25)
self.assertEqual(fullrepr, s.getvalue())[](#l5.26)
- def test_as_bytes(self):
msg = self._msgobj('msg_01.txt')[](#l5.29)
with openfile('msg_01.txt', 'rb') as fp:[](#l5.30)
data = fp.read()[](#l5.31)
self.assertEqual(data, bytes(msg))[](#l5.32)
fullrepr = msg.as_bytes(unixfrom=True)[](#l5.33)
lines = fullrepr.split(b'\n')[](#l5.34)
self.assertTrue(lines[0].startswith(b'From '))[](#l5.35)
self.assertEqual(data, b'\n'.join(lines[1:]))[](#l5.36)
- def test_as_bytes_policy(self):
msg = self._msgobj('msg_01.txt')[](#l5.39)
newpolicy = msg.policy.clone(linesep='\r\n')[](#l5.40)
fullrepr = msg.as_bytes(policy=newpolicy)[](#l5.41)
s = BytesIO()[](#l5.42)
g = BytesGenerator(s,policy=newpolicy)[](#l5.43)
g.flatten(msg)[](#l5.44)
self.assertEqual(fullrepr, s.getvalue())[](#l5.45)
# test_headerregistry.TestContentTypeHeader.bad_params def test_bad_param(self):
--- a/Misc/NEWS +++ b/Misc/NEWS @@ -22,6 +22,9 @@ Core and Builtins Library ------- +- Issue #18600: Added policy argument to email.message.Message.as_string,