[Python-checkins] [3.6] bpo-34246: Use no mutable default args in smtplib (GH-8554) (#9112)

Pablo Galindo webhook-mailer at python.org
Fri Sep 7 21:20:31 EDT 2018


https://github.com/python/cpython/commit/eb6ab73f93c8b883a8d75a83560e2b4c59170d95
commit: eb6ab73f93c8b883a8d75a83560e2b4c59170d95
branch: 3.6
author: Pablo Galindo <Pablogsal at gmail.com>
committer: GitHub <noreply at github.com>
date: 2018年09月08日T02:20:27+01:00
summary:
[3.6] bpo-34246: Use no mutable default args in smtplib (GH-8554) (#9112)
Some methods of the SMTP class use mutable default arguments. Specially
`send_message` is affected as it mutates one of the args by appending items
to it, which has side effects on further calls..
(cherry picked from commit d5fbe9b1a3d65ceeb9159c5ba999ee966a945f76)
Co-authored-by: Pablo Aguiar <scorphus at gmail.com>
files:
A Misc/NEWS.d/next/Library/2018-07-29-15-25-15.bpo-34246.xiKq-Q.rst
M Doc/library/smtplib.rst
M Lib/smtplib.py
M Lib/test/test_smtplib.py
M Misc/ACKS
diff --git a/Doc/library/smtplib.rst b/Doc/library/smtplib.rst
index e5effd0306a4..805217252ae8 100644
--- a/Doc/library/smtplib.rst
+++ b/Doc/library/smtplib.rst
@@ -419,7 +419,7 @@ An :class:`SMTP` instance has the following methods:
 :exc:`SMTPException`.
 
 
-.. method:: SMTP.sendmail(from_addr, to_addrs, msg, mail_options=[], rcpt_options=[])
+.. method:: SMTP.sendmail(from_addr, to_addrs, msg, mail_options=(), rcpt_options=())
 
 Send mail. The required arguments are an :rfc:`822` from-address string, a list
 of :rfc:`822` to-address strings (a bare string will be treated as a list with 1
@@ -491,7 +491,7 @@ An :class:`SMTP` instance has the following methods:
 
 
 .. method:: SMTP.send_message(msg, from_addr=None, to_addrs=None, \
- mail_options=[], rcpt_options=[])
+ mail_options=(), rcpt_options=())
 
 This is a convenience method for calling :meth:`sendmail` with the message
 represented by an :class:`email.message.Message` object. The arguments have
diff --git a/Lib/smtplib.py b/Lib/smtplib.py
index b679875fd2c5..048c6bfb0671 100755
--- a/Lib/smtplib.py
+++ b/Lib/smtplib.py
@@ -513,7 +513,7 @@ def noop(self):
 """SMTP 'noop' command -- doesn't do anything :>"""
 return self.docmd("noop")
 
- def mail(self, sender, options=[]):
+ def mail(self, sender, options=()):
 """SMTP 'mail' command -- begins mail xfer session.
 
 This method may raise the following exceptions:
@@ -534,7 +534,7 @@ def mail(self, sender, options=[]):
 self.putcmd("mail", "FROM:%s%s" % (quoteaddr(sender), optionlist))
 return self.getreply()
 
- def rcpt(self, recip, options=[]):
+ def rcpt(self, recip, options=()):
 """SMTP 'rcpt' command -- indicates 1 recipient for this mail."""
 optionlist = ''
 if options and self.does_esmtp:
@@ -785,8 +785,8 @@ def starttls(self, keyfile=None, certfile=None, context=None):
 raise SMTPResponseException(resp, reply)
 return (resp, reply)
 
- def sendmail(self, from_addr, to_addrs, msg, mail_options=[],
- rcpt_options=[]):
+ def sendmail(self, from_addr, to_addrs, msg, mail_options=(),
+ rcpt_options=()):
 """This command performs an entire mail transaction.
 
 The arguments are:
@@ -890,7 +890,7 @@ def sendmail(self, from_addr, to_addrs, msg, mail_options=[],
 return senderrs
 
 def send_message(self, msg, from_addr=None, to_addrs=None,
- mail_options=[], rcpt_options={}):
+ mail_options=(), rcpt_options=()):
 """Converts message to a bytestring and passes it to sendmail.
 
 The arguments are as for sendmail, except that msg is an
@@ -958,7 +958,7 @@ def send_message(self, msg, from_addr=None, to_addrs=None,
 if international:
 g = email.generator.BytesGenerator(
 bytesmsg, policy=msg.policy.clone(utf8=True))
- mail_options += ['SMTPUTF8', 'BODY=8BITMIME']
+ mail_options = (*mail_options, 'SMTPUTF8', 'BODY=8BITMIME')
 else:
 g = email.generator.BytesGenerator(bytesmsg)
 g.flatten(msg_copy, linesep='\r\n')
diff --git a/Lib/test/test_smtplib.py b/Lib/test/test_smtplib.py
index 79b3bd436876..18110191dc3b 100644
--- a/Lib/test/test_smtplib.py
+++ b/Lib/test/test_smtplib.py
@@ -18,6 +18,11 @@
 
 import unittest
 from test import support, mock_socket
+from unittest.mock import Mock
+
+HOST = "localhost"
+HOSTv4 = "127.0.0.1"
+HOSTv6 = "::1"
 
 try:
 import threading
@@ -569,6 +574,33 @@ def testNonnumericPort(self):
 "localhost:bogus")
 
 
+class DefaultArgumentsTests(unittest.TestCase):
+
+ def setUp(self):
+ self.msg = EmailMessage()
+ self.msg['From'] = 'Páolo <főo at bar.com>'
+ self.smtp = smtplib.SMTP()
+ self.smtp.ehlo = Mock(return_value=(200, 'OK'))
+ self.smtp.has_extn, self.smtp.sendmail = Mock(), Mock()
+
+ def testSendMessage(self):
+ expected_mail_options = ('SMTPUTF8', 'BODY=8BITMIME')
+ self.smtp.send_message(self.msg)
+ self.smtp.send_message(self.msg)
+ self.assertEqual(self.smtp.sendmail.call_args_list[0][0][3],
+ expected_mail_options)
+ self.assertEqual(self.smtp.sendmail.call_args_list[1][0][3],
+ expected_mail_options)
+
+ def testSendMessageWithMailOptions(self):
+ mail_options = ['STARTTLS']
+ expected_mail_options = ('STARTTLS', 'SMTPUTF8', 'BODY=8BITMIME')
+ self.smtp.send_message(self.msg, None, None, mail_options)
+ self.assertEqual(mail_options, ['STARTTLS'])
+ self.assertEqual(self.smtp.sendmail.call_args_list[0][0][3],
+ expected_mail_options)
+
+
 # test response of client to a non-successful HELO message
 @unittest.skipUnless(threading, 'Threading required for this test.')
 class BadHELOServerTests(unittest.TestCase):
diff --git a/Misc/ACKS b/Misc/ACKS
index 64a007236b65..bd8a5fb81f0f 100644
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -21,6 +21,7 @@ Ron Adam
 Anton Afanasyev
 Ali Afshar
 Nitika Agarwal
+Pablo S. Blum de Aguiar
 Jim Ahlstrom
 Farhan Ahmad
 Matthew Ahrens
diff --git a/Misc/NEWS.d/next/Library/2018-07-29-15-25-15.bpo-34246.xiKq-Q.rst b/Misc/NEWS.d/next/Library/2018-07-29-15-25-15.bpo-34246.xiKq-Q.rst
new file mode 100644
index 000000000000..50c91ece07ef
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2018-07-29-15-25-15.bpo-34246.xiKq-Q.rst
@@ -0,0 +1,2 @@
+:meth:`smtplib.SMTP.send_message` no longer modifies the content of the
+*mail_options* argument. Patch by Pablo S. Blum de Aguiar.


More information about the Python-checkins mailing list

AltStyle によって変換されたページ (->オリジナル) /