diff -r 751328f413a8 Doc/library/email.errors.rst --- a/Doc/library/email.errors.rst Sat Aug 02 22:32:33 2014 -0700 +++ b/Doc/library/email.errors.rst Mon Aug 04 15:16:25 2014 +0300 @@ -101,8 +101,8 @@ * :class:`MultipartInvariantViolationDefect` -- A message claimed to be a :mimetype:`multipart`, but no subparts were found. Note that when a message - has this defect, its :meth:`~email.message.Message.is_multipart` method may - return false even though its content type claims to be :mimetype:`multipart`. + has this defect, its :attr:`~email.message.Message.is_multipart` property may + be false even though its content type claims to be :mimetype:`multipart`. * :class:`InvalidBase64PaddingDefect` -- When decoding a block of base64 enocded bytes, the padding was not correct. Enough padding is added to diff -r 751328f413a8 Doc/library/email.message.rst --- a/Doc/library/email.message.rst Sat Aug 02 22:32:33 2014 -0700 +++ b/Doc/library/email.message.rst Mon Aug 04 15:16:25 2014 +0300 @@ -127,11 +127,13 @@ .. versionadded:: 3.4 - .. method:: is_multipart() + .. attribute:: is_multipart - Return ``True`` if the message's payload is a list of sub-\ - :class:`Message` objects, otherwise return ``False``. When - :meth:`is_multipart` returns ``False``, the payload should be a string object. + Set to ``True`` if the message's payload is a list of sub-:class:`Message` + objects, otherwise ``False``. When :attr:`is_multipart` is set to + ``False``, the payload should be a string object. + + .. versionchanged:: 3.5 Changed from a method to a property. .. method:: set_unixfrom(unixfrom) @@ -157,15 +159,15 @@ .. method:: get_payload(i=None, decode=False) Return the current payload, which will be a list of - :class:`Message` objects when :meth:`is_multipart` is ``True``, or a - string when :meth:`is_multipart` is ``False``. If the payload is a list + :class:`Message` objects when :attr:`is_multipart` is ``True``, or a + string when :attr:`is_multipart` is ``False``. If the payload is a list and you mutate the list object, you modify the message's payload in place. With optional argument *i*, :meth:`get_payload` will return the *i*-th - element of the payload, counting from zero, if :meth:`is_multipart` is + element of the payload, counting from zero, if :attr:`is_multipart` is ``True``. An :exc:`IndexError` will be raised if *i* is less than 0 or greater than or equal to the number of items in the payload. If the - payload is a string (i.e. :meth:`is_multipart` is ``False``) and *i* is + payload is a string (i.e. :attr:`is_multipart` is ``False``) and *i* is given, a :exc:`TypeError` is raised. Optional *decode* is a flag indicating whether the payload should be diff -r 751328f413a8 Doc/library/email.parser.rst --- a/Doc/library/email.parser.rst Sat Aug 02 22:32:33 2014 -0700 +++ b/Doc/library/email.parser.rst Mon Aug 04 15:16:25 2014 +0300 @@ -17,7 +17,7 @@ :class:`~email.message.Message` instance of the object structure. For simple, non-MIME messages the payload of this root object will likely be a string containing the text of the message. For MIME messages, the root object will -return ``True`` from its :meth:`~email.message.Message.is_multipart` method, and +return ``True`` from its :attr:`~email.message.Message.is_multipart` property, and the subparts can be accessed via the :meth:`~email.message.Message.get_payload` and :meth:`~email.message.Message.walk` methods. @@ -275,26 +275,26 @@ * Most non-\ :mimetype:`multipart` type messages are parsed as a single message object with a string payload. These objects will return ``False`` for - :meth:`~email.message.Message.is_multipart`. Their + :attr:`~email.message.Message.is_multipart`. Their :meth:`~email.message.Message.get_payload` method will return a string object. * All :mimetype:`multipart` type messages will be parsed as a container message object with a list of sub-message objects for their payload. The outer container message will return ``True`` for - :meth:`~email.message.Message.is_multipart` and their + :attr:`~email.message.Message.is_multipart` and their :meth:`~email.message.Message.get_payload` method will return the list of :class:`~email.message.Message` subparts. * Most messages with a content type of :mimetype:`message/\*` (e.g. :mimetype:`message/delivery-status` and :mimetype:`message/rfc822`) will also be parsed as container object containing a list payload of length 1. Their - :meth:`~email.message.Message.is_multipart` method will return ``True``. + :attr:`~email.message.Message.is_multipart` property will be ``True``. The single element in the list payload will be a sub-message object. * Some non-standards compliant messages may not be internally consistent about their :mimetype:`multipart`\ -edness. Such messages may have a :mailheader:`Content-Type` header of type :mimetype:`multipart`, but their - :meth:`~email.message.Message.is_multipart` method may return ``False``. + :attr:`~email.message.Message.is_multipart` property may be ``False``. If such messages were parsed with the :class:`~email.parser.FeedParser`, they will have an instance of the :class:`~email.errors.MultipartInvariantViolationDefect` class in their diff -r 751328f413a8 Doc/library/email.rst --- a/Doc/library/email.rst Sat Aug 02 22:32:33 2014 -0700 +++ b/Doc/library/email.rst Mon Aug 04 15:16:25 2014 +0300 @@ -205,14 +205,14 @@ * The object structure has changed in the face of :mimetype:`message/rfc822` content types. In :mod:`email` version 1, such a type would be represented by a scalar payload, i.e. the container message's - :meth:`~email.message.Message.is_multipart` returned false, + :attr:`~email.message.Message.is_multipart` is false, :meth:`~email.message.Message.get_payload` was not a list object, but a single :class:`~email.message.Message` instance. This structure was inconsistent with the rest of the package, so the object representation for :mimetype:`message/rfc822` content types was changed. In :mod:`email` version 2, the container *does* return ``True`` from - :meth:`~email.message.Message.is_multipart`, and + :attr:`~email.message.Message.is_multipart`, and :meth:`~email.message.Message.get_payload` returns a list containing a single :class:`~email.message.Message` item. @@ -283,7 +283,7 @@ :meth:`~email.message.Message.as_string`. * The method :meth:`ismultipart` was renamed to - :meth:`~email.message.Message.is_multipart`. + :attr:`~email.message.Message.is_multipart`, and became a property. * The :meth:`~email.message.Message.get_payload` method has grown a *decode* optional argument. diff -r 751328f413a8 Lib/email/feedparser.py --- a/Lib/email/feedparser.py Sat Aug 02 22:32:33 2014 -0700 +++ b/Lib/email/feedparser.py Mon Aug 04 15:16:25 2014 +0300 @@ -181,7 +181,7 @@ assert not self._msgstack # Look for final set of defects if root.get_content_maintype() == 'multipart' \ - and not root.is_multipart(): + and not root.is_multipart: defect = errors.MultipartInvariantViolationDefect() self.policy.handle_defect(root, defect) return root diff -r 751328f413a8 Lib/email/iterators.py --- a/Lib/email/iterators.py Sat Aug 02 22:32:33 2014 -0700 +++ b/Lib/email/iterators.py Mon Aug 04 15:16:25 2014 +0300 @@ -24,7 +24,7 @@ generator. """ yield self - if self.is_multipart(): + if self.is_multipart: for subpart in self.get_payload(): yield from subpart.walk() @@ -66,6 +66,6 @@ print(' [%s]' % msg.get_default_type(), file=fp) else: print(file=fp) - if msg.is_multipart(): + if msg.is_multipart: for subpart in msg.get_payload(): _structure(subpart, fp, level+1, include_default) diff -r 751328f413a8 Lib/email/message.py --- a/Lib/email/message.py Sat Aug 02 22:32:33 2014 -0700 +++ b/Lib/email/message.py Mon Aug 04 15:16:25 2014 +0300 @@ -101,6 +101,32 @@ return utils.unquote(value) +class CallableBool(int): + def __new__(cls, value, name): + self = super(CallableBool, cls).__new__(cls, bool(value)) + self._name = name + return self + + def __call__(self): + import warnings + warnings.warn + warnings.warn('%s is a property now' % self._name, + DeprecationWarning, stacklevel=2) + return bool(self) + + def __repr__(self): + return repr(bool(self)) + + def __and__(self, other): + return bool(self).__and__(other) + + def __or__(self, other): + return bool(self).__or__(other) + + def __xor__(self, other): + return bool(self).__xor__(other) + + class Message: """Basic message object. @@ -178,9 +204,10 @@ g.flatten(self, unixfrom=unixfrom) return fp.getvalue() + @property def is_multipart(self): """Return True if the message consists of multiple parts.""" - return isinstance(self._payload, list) + return CallableBool(isinstance(self._payload, list), 'is_multipart') # # Unix From_ line @@ -244,7 +271,7 @@ # Note that Barry planned to factor out the 'decode' case, but that # isn't so easy now that we handle the 8 bit data, which needs to be # converted in both the decode and non-decode path. - if self.is_multipart(): + if self.is_multipart: if decode: return None if i is None: diff -r 751328f413a8 Lib/test/test_email/test_email.py --- a/Lib/test/test_email/test_email.py Sat Aug 02 22:32:33 2014 -0700 +++ b/Lib/test/test_email/test_email.py Mon Aug 04 15:16:25 2014 +0300 @@ -1628,7 +1628,7 @@ def test_payload(self): self.assertEqual(self._msg.get_payload(), 'hello there') - self.assertFalse(self._msg.is_multipart()) + self.assertFalse(self._msg.is_multipart) def test_charset(self): eq = self.assertEqual @@ -1709,7 +1709,7 @@ raises = self.assertRaises # tests m = self._msg - self.assertTrue(m.is_multipart()) + self.assertTrue(m.is_multipart) eq(m.get_content_type(), 'multipart/mixed') eq(len(m.get_payload()), 2) raises(IndexError, m.get_payload, 2) @@ -1718,8 +1718,8 @@ self.assertIs(m0, self._txt) self.assertIs(m1, self._im) eq(m.get_payload(), [m0, m1]) - self.assertFalse(m0.is_multipart()) - self.assertFalse(m1.is_multipart()) + self.assertFalse(m0.is_multipart) + self.assertFalse(m1.is_multipart) def test_empty_multipart_idempotent(self): text = """\ @@ -2024,7 +2024,7 @@ -- XXXX-- ''') - self.assertTrue(msg.is_multipart()) + self.assertTrue(msg.is_multipart) eq(msg.get_boundary(), ' XXXX') eq(len(msg.get_payload()), 2) @@ -2416,7 +2416,7 @@ # msg 16 is a Delivery Status Notification, see RFC 1894 msg = self._msgobj('msg_16.txt') eq(msg.get_content_type(), 'multipart/report') - self.assertTrue(msg.is_multipart()) + self.assertTrue(msg.is_multipart) eq(len(msg.get_payload()), 3) # Subpart 1 is a text/plain, human readable section subpart = msg.get_payload(0) @@ -2642,7 +2642,7 @@ def test_default_multipart_constructor(self): msg = MIMEMultipart() - self.assertTrue(msg.is_multipart()) + self.assertTrue(msg.is_multipart) # A general test of parser->model->generator idempotency. IOW, read a message @@ -3375,7 +3375,7 @@ eq(msg['from'], 'ppp-request@zzz.org') eq(msg['to'], 'ppp@zzz.org') eq(msg.get_content_type(), 'multipart/mixed') - self.assertFalse(msg.is_multipart()) + self.assertFalse(msg.is_multipart) self.assertIsInstance(msg.get_payload(), str) def test_bytes_header_parser(self): @@ -3386,7 +3386,7 @@ eq(msg['from'], 'ppp-request@zzz.org') eq(msg['to'], 'ppp@zzz.org') eq(msg.get_content_type(), 'multipart/mixed') - self.assertFalse(msg.is_multipart()) + self.assertFalse(msg.is_multipart) self.assertIsInstance(msg.get_payload(), str) self.assertIsInstance(msg.get_payload(decode=True), bytes) @@ -3485,23 +3485,23 @@ # text/plain # message/rfc822 # text/plain - eq(msg.is_multipart(), 1) + eq(msg.is_multipart, 1) eq(len(msg.get_payload()), 2) part1 = msg.get_payload(0) eq(part1.get_content_type(), 'message/rfc822') - eq(part1.is_multipart(), 1) + eq(part1.is_multipart, 1) eq(len(part1.get_payload()), 1) part1a = part1.get_payload(0) - eq(part1a.is_multipart(), 0) + eq(part1a.is_multipart, 0) eq(part1a.get_content_type(), 'text/plain') neq(part1a.get_payload(), 'message 1\n') # next message/rfc822 part2 = msg.get_payload(1) eq(part2.get_content_type(), 'message/rfc822') - eq(part2.is_multipart(), 1) + eq(part2.is_multipart, 1) eq(len(part2.get_payload()), 1) part2a = part2.get_payload(0) - eq(part2a.is_multipart(), 0) + eq(part2a.is_multipart, 0) eq(part2a.get_content_type(), 'text/plain') neq(part2a.get_payload(), 'message 2\n') diff -r 751328f413a8 Lib/test/test_email/test_message.py --- a/Lib/test/test_email/test_message.py Sat Aug 02 22:32:33 2014 -0700 +++ b/Lib/test/test_email/test_message.py Mon Aug 04 15:16:25 2014 +0300 @@ -646,8 +646,13 @@ m['Content-Type'] = 'text/plain' elif subtype != 'no_content': m['Content-Type'] = 'multipart/' + subtype + self.assertFalse(m.is_multipart) + with self.assertWarns(DeprecationWarning): + self.assertFalse(m.is_multipart()) getattr(m, 'make_' + method)(boundary="abc") - self.assertTrue(m.is_multipart()) + self.assertTrue(m.is_multipart) + with self.assertWarns(DeprecationWarning): + self.assertTrue(m.is_multipart()) self.assertEqual(m.get_boundary(), 'abc') def test_policy_on_part_made_by_make_comes_from_message(self): diff -r 751328f413a8 Lib/test/test_mailbox.py --- a/Lib/test/test_mailbox.py Sat Aug 02 22:32:33 2014 -0700 +++ b/Lib/test/test_mailbox.py Mon Aug 04 15:16:25 2014 +0300 @@ -32,7 +32,7 @@ self.assertIsInstance(msg, mailbox.Message) for key, value in _sample_headers.items(): self.assertIn(value, msg.get_all(key)) - self.assertTrue(msg.is_multipart()) + self.assertTrue(msg.is_multipart) self.assertEqual(len(msg.get_payload()), len(_sample_payloads)) for i, payload in enumerate(_sample_payloads): part = msg.get_payload(i) @@ -1393,7 +1393,7 @@ self.assertIsInstance(msg, mailbox.Message) self.assertIsInstance(msg, self._factory) self.assertEqual(msg.keys(), []) - self.assertFalse(msg.is_multipart()) + self.assertFalse(msg.is_multipart) self.assertIsNone(msg.get_payload()) def test_initialize_incorrectly(self):