#21091: make is_attachment a method.

Since EmailMessage is a provisional API we can fix API bugs in a
maintenance release, but I used a trick suggested by Serhiy to
maintain backward compatibility with 3.4.0/1.
This commit is contained in:
R David Murray 2014-09-20 18:05:28 -04:00
parent 97dfad7856
commit 8a97896a76
4 changed files with 43 additions and 10 deletions

View File

@ -70,11 +70,15 @@ this module.
the following methods:
.. attribute:: is_attachment
.. method:: is_attachment
Set to ``True`` if there is a :mailheader:`Content-Disposition` header
Return ``True`` if there is a :mailheader:`Content-Disposition` header
and its (case insensitive) value is ``attachment``, ``False`` otherwise.
.. versionchanged:: 3.4.2
is_attachment is now a method instead of a property, for consistency
with :meth:`~email.message.Message.is_multipart`.
.. method:: get_body(preferencelist=('related', 'html', 'plain'))

View File

@ -9,6 +9,7 @@ __all__ = ['Message']
import re
import uu
import quopri
import warnings
from io import BytesIO, StringIO
# Intrapackage imports
@ -929,6 +930,17 @@ class Message:
# I.e. def walk(self): ...
from email.iterators import walk
# XXX Support for temporary deprecation hack for is_attachment property.
class _IsAttachment:
def __init__(self, value):
self.value = value
def __call__(self):
return self.value
def __bool__(self):
warnings.warn("is_attachment will be a method, not a property, in 3.5",
DeprecationWarning,
stacklevel=3)
return self.value
class MIMEPart(Message):
@ -941,10 +953,12 @@ class MIMEPart(Message):
@property
def is_attachment(self):
c_d = self.get('content-disposition')
return False if c_d is None else c_d.content_disposition == 'attachment'
result = False if c_d is None else c_d.content_disposition == 'attachment'
# XXX transitional hack to raise deprecation if not called.
return _IsAttachment(result)
def _find_body(self, part, preferencelist):
if part.is_attachment:
if part.is_attachment():
return
maintype, subtype = part.get_content_type().split('/')
if maintype == 'text':
@ -1037,7 +1051,7 @@ class MIMEPart(Message):
for part in parts:
maintype, subtype = part.get_content_type().split('/')
if ((maintype, subtype) in self._body_types and
not part.is_attachment and subtype not in seen):
not part.is_attachment() and subtype not in seen):
seen.append(subtype)
continue
yield part

View File

@ -722,15 +722,25 @@ class TestEmailMessageBase:
def test_is_attachment(self):
m = self._make_message()
self.assertFalse(m.is_attachment)
self.assertFalse(m.is_attachment())
with self.assertWarns(DeprecationWarning):
self.assertFalse(m.is_attachment)
m['Content-Disposition'] = 'inline'
self.assertFalse(m.is_attachment)
self.assertFalse(m.is_attachment())
with self.assertWarns(DeprecationWarning):
self.assertFalse(m.is_attachment)
m.replace_header('Content-Disposition', 'attachment')
self.assertTrue(m.is_attachment)
self.assertTrue(m.is_attachment())
with self.assertWarns(DeprecationWarning):
self.assertTrue(m.is_attachment)
m.replace_header('Content-Disposition', 'AtTachMent')
self.assertTrue(m.is_attachment)
self.assertTrue(m.is_attachment())
with self.assertWarns(DeprecationWarning):
self.assertTrue(m.is_attachment)
m.set_param('filename', 'abc.png', 'Content-Disposition')
self.assertTrue(m.is_attachment)
self.assertTrue(m.is_attachment())
with self.assertWarns(DeprecationWarning):
self.assertTrue(m.is_attachment)
class TestEmailMessage(TestEmailMessageBase, TestEmailBase):

View File

@ -32,6 +32,11 @@ Core and Builtins
Library
-------
- Issue #21091: Fix API bug: email.message.EmailMessage.is_attachment is now
a method. Since EmailMessage is provisional, we can change the API in a
maintenance release, but we use a trick to remain backward compatible with
3.4.0/1.
- Issue #21079: Fix email.message.EmailMessage.is_attachment to return the
correct result when the header has parameters as well as a value.