[Python-checkins] cpython (merge default -> default): merge
brett.cannon
python-checkins at python.org
Tue Mar 15 21:03:43 CET 2011
http://hg.python.org/cpython/rev/e04253f3ad4a
changeset: 68532:e04253f3ad4a
parent: 68531:07f5ec8fc014
parent: 68528:fbdcc7437b34
user: Brett Cannon <brett at python.org>
date: Tue Mar 15 16:03:32 2011 -0400
summary:
merge
files:
diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst
--- a/Doc/c-api/init.rst
+++ b/Doc/c-api/init.rst
@@ -537,9 +537,10 @@
operations such as ``PyEval_ReleaseThread(tstate)``. It is not needed before
calling :c:func:`PyEval_SaveThread` or :c:func:`PyEval_RestoreThread`.
- .. index:: single: Py_Initialize()
+ This is a no-op when called for a second time.
- This is a no-op when called for a second time.
+ .. versionchanged:: 3.2
+ This function cannot be called before :c:func:`Py_Initialize()` anymore.
.. index:: module: _thread
diff --git a/Doc/library/smtplib.rst b/Doc/library/smtplib.rst
--- a/Doc/library/smtplib.rst
+++ b/Doc/library/smtplib.rst
@@ -34,6 +34,20 @@
For normal use, you should only require the initialization/connect,
:meth:`sendmail`, and :meth:`quit` methods. An example is included below.
+ The :class:`SMTP` class supports the :keyword:`with` statement. When used
+ like this, the SMTP ``QUIT`` command is issued automatically when the
+ :keyword:`with` statement exits. E.g.::
+
+ >>> from smtplib import SMTP
+ >>> with SMTP("domain.org") as smtp:
+ ... smtp.noop()
+ ...
+ (250, b'Ok')
+ >>>
+
+ .. versionadded:: 3.3
+ Support for the :keyword:`with` statement was added.
+
.. class:: SMTP_SSL(host='', port=0, local_hostname=None, keyfile=None, certfile=None[, timeout])
diff --git a/Doc/whatsnew/3.2.rst b/Doc/whatsnew/3.2.rst
--- a/Doc/whatsnew/3.2.rst
+++ b/Doc/whatsnew/3.2.rst
@@ -2698,3 +2698,7 @@
a new function, :func:`asyncore.handle_accepted`, was added to replace it.
(Contributed by Giampaolo Rodola in :issue:`6706`.)
+
+* Due to the new :term:`GIL` implementation, :c:func:`PyEval_InitThreads()`
+ cannot be called before :c:func:`Py_Initialize()` anymore.
+
diff --git a/Lib/smtplib.py b/Lib/smtplib.py
--- a/Lib/smtplib.py
+++ b/Lib/smtplib.py
@@ -269,6 +269,19 @@
pass
self.local_hostname = '[%s]' % addr
+ def __enter__(self):
+ return self
+
+ def __exit__(self, *args):
+ try:
+ code, message = self.docmd("QUIT")
+ if code != 221:
+ raise SMTPResponseException(code, message)
+ except SMTPServerDisconnected:
+ pass
+ finally:
+ self.close()
+
def set_debuglevel(self, debuglevel):
"""Set the debug output level.
diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py
--- a/Lib/test/test_dis.py
+++ b/Lib/test/test_dis.py
@@ -1,11 +1,35 @@
# Minimal tests for dis module
from test.support import run_unittest, captured_stdout
+import difflib
import unittest
import sys
import dis
import io
+class _C:
+ def __init__(self, x):
+ self.x = x == 1
+
+dis_c_instance_method = """\
+ %-4d 0 LOAD_FAST 1 (x)
+ 3 LOAD_CONST 1 (1)
+ 6 COMPARE_OP 2 (==)
+ 9 LOAD_FAST 0 (self)
+ 12 STORE_ATTR 0 (x)
+ 15 LOAD_CONST 0 (None)
+ 18 RETURN_VALUE
+""" % (_C.__init__.__code__.co_firstlineno + 1,)
+
+dis_c_instance_method_bytes = """\
+ 0 LOAD_FAST 1 (1)
+ 3 LOAD_CONST 1 (1)
+ 6 COMPARE_OP 2 (==)
+ 9 LOAD_FAST 0 (0)
+ 12 STORE_ATTR 0 (0)
+ 15 LOAD_CONST 0 (0)
+ 18 RETURN_VALUE
+"""
def _f(a):
print(a)
@@ -23,6 +47,16 @@
_f.__code__.co_firstlineno + 2)
+dis_f_co_code = """\
+ 0 LOAD_GLOBAL 0 (0)
+ 3 LOAD_FAST 0 (0)
+ 6 CALL_FUNCTION 1
+ 9 POP_TOP
+ 10 LOAD_CONST 1 (1)
+ 13 RETURN_VALUE
+"""
+
+
def bug708901():
for res in range(1,
10):
@@ -138,18 +172,27 @@
"""
class DisTests(unittest.TestCase):
- def do_disassembly_test(self, func, expected):
+
+ def get_disassembly(self, func, lasti=-1, wrapper=True):
s = io.StringIO()
save_stdout = sys.stdout
sys.stdout = s
- dis.dis(func)
- sys.stdout = save_stdout
- got = s.getvalue()
+ try:
+ if wrapper:
+ dis.dis(func)
+ else:
+ dis.disassemble(func, lasti)
+ finally:
+ sys.stdout = save_stdout
# Trim trailing blanks (if any).
- lines = got.split('\n')
- lines = [line.rstrip() for line in lines]
- expected = expected.split("\n")
- import difflib
+ return [line.rstrip() for line in s.getvalue().splitlines()]
+
+ def get_disassemble_as_string(self, func, lasti=-1):
+ return '\n'.join(self.get_disassembly(func, lasti, False))
+
+ def do_disassembly_test(self, func, expected):
+ lines = self.get_disassembly(func)
+ expected = expected.splitlines()
if expected != lines:
self.fail(
"events did not match expectation:\n" +
@@ -211,6 +254,46 @@
self.do_disassembly_test(simple_stmt_str, dis_simple_stmt_str)
self.do_disassembly_test(compound_stmt_str, dis_compound_stmt_str)
+ def test_disassemble_bytes(self):
+ self.do_disassembly_test(_f.__code__.co_code, dis_f_co_code)
+
+ def test_disassemble_method(self):
+ self.do_disassembly_test(_C(1).__init__, dis_c_instance_method)
+
+ def test_disassemble_method_bytes(self):
+ method_bytecode = _C(1).__init__.__code__.co_code
+ self.do_disassembly_test(method_bytecode, dis_c_instance_method_bytes)
+
+ def test_dis_none(self):
+ self.assertRaises(RuntimeError, dis.dis, None)
+
+ def test_dis_object(self):
+ self.assertRaises(TypeError, dis.dis, object())
+
+ def test_dis_traceback(self):
+ not_defined = object()
+ tb = None
+ old = getattr(sys, 'last_traceback', not_defined)
+
+ def cleanup():
+ if old != not_defined:
+ sys.last_traceback = old
+ else:
+ del sys.last_traceback
+
+ try:
+ 1/0
+ except Exception as e:
+ tb = e.__traceback__
+ sys.last_traceback = tb
+ self.addCleanup(cleanup)
+
+ tb_dis = self.get_disassemble_as_string(tb.tb_frame.f_code, tb.tb_lasti)
+ self.do_disassembly_test(None, tb_dis)
+
+ def test_dis_object(self):
+ self.assertRaises(TypeError, dis.dis, object())
+
code_info_code_info = """\
Name: code_info
Filename: (.*)
@@ -363,6 +446,13 @@
dis.show_code(x)
self.assertRegex(output.getvalue(), expected+"\n")
+ def test_code_info_object(self):
+ self.assertRaises(TypeError, dis.code_info, object())
+
+ def test_pretty_flags_no_flags(self):
+ self.assertEqual(dis.pretty_flags(0), '0x0')
+
+
def test_main():
run_unittest(DisTests, CodeInfoTests)
diff --git a/Lib/test/test_smtplib.py b/Lib/test/test_smtplib.py
--- a/Lib/test/test_smtplib.py
+++ b/Lib/test/test_smtplib.py
@@ -424,6 +424,9 @@
# Simulated SMTP channel & server
class SimSMTPChannel(smtpd.SMTPChannel):
+ # For testing failures in QUIT when using the context manager API.
+ quit_response = None
+
def __init__(self, extra_features, *args, **kw):
self._extrafeatures = ''.join(
[ "250-{0}\r\n".format(x) for x in extra_features ])
@@ -475,19 +478,31 @@
else:
self.push('550 No access for you!')
+ def smtp_QUIT(self, arg):
+ # args is ignored
+ if self.quit_response is None:
+ super(SimSMTPChannel, self).smtp_QUIT(arg)
+ else:
+ self.push(self.quit_response)
+ self.close_when_done()
+
def handle_error(self):
raise
class SimSMTPServer(smtpd.SMTPServer):
+ # For testing failures in QUIT when using the context manager API.
+ quit_response = None
+
def __init__(self, *args, **kw):
self._extra_features = []
smtpd.SMTPServer.__init__(self, *args, **kw)
def handle_accepted(self, conn, addr):
- self._SMTPchannel = SimSMTPChannel(self._extra_features,
- self, conn, addr)
+ self._SMTPchannel = SimSMTPChannel(
+ self._extra_features, self, conn, addr)
+ self._SMTPchannel.quit_response = self.quit_response
def process_message(self, peer, mailfrom, rcpttos, data):
pass
@@ -620,6 +635,25 @@
self.assertIn(sim_auth_credentials['cram-md5'], str(err))
smtp.close()
+ def test_with_statement(self):
+ with smtplib.SMTP(HOST, self.port) as smtp:
+ code, message = smtp.noop()
+ self.assertEqual(code, 250)
+ self.assertRaises(smtplib.SMTPServerDisconnected, smtp.send, b'foo')
+ with smtplib.SMTP(HOST, self.port) as smtp:
+ smtp.close()
+ self.assertRaises(smtplib.SMTPServerDisconnected, smtp.send, b'foo')
+
+ def test_with_statement_QUIT_failure(self):
+ self.serv.quit_response = '421 QUIT FAILED'
+ with self.assertRaises(smtplib.SMTPResponseException) as error:
+ with smtplib.SMTP(HOST, self.port) as smtp:
+ smtp.noop()
+ self.assertEqual(error.exception.smtp_code, 421)
+ self.assertEqual(error.exception.smtp_error, b'QUIT FAILED')
+ # We don't need to clean up self.serv.quit_response because a new
+ # server is always instantiated in the setUp().
+
#TODO: add tests for correct AUTH method fallback now that the
#test infrastructure can support it.
diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py
--- a/Lib/test/test_subprocess.py
+++ b/Lib/test/test_subprocess.py
@@ -3,6 +3,7 @@
import subprocess
import sys
import signal
+import io
import os
import errno
import tempfile
@@ -1256,6 +1257,24 @@
close_fds=False, pass_fds=(fd, )))
self.assertIn('overriding close_fds', str(context.warning))
+ def test_stdout_stdin_are_single_inout_fd(self):
+ with io.open(os.devnull, "r+") as inout:
+ p = subprocess.Popen([sys.executable, "-c", "import sys; sys.exit(0)"],
+ stdout=inout, stdin=inout)
+ p.wait()
+
+ def test_stdout_stderr_are_single_inout_fd(self):
+ with io.open(os.devnull, "r+") as inout:
+ p = subprocess.Popen([sys.executable, "-c", "import sys; sys.exit(0)"],
+ stdout=inout, stderr=inout)
+ p.wait()
+
+ def test_stderr_stdin_are_single_inout_fd(self):
+ with io.open(os.devnull, "r+") as inout:
+ p = subprocess.Popen([sys.executable, "-c", "import sys; sys.exit(0)"],
+ stderr=inout, stdin=inout)
+ p.wait()
+
def test_wait_when_sigchild_ignored(self):
# NOTE: sigchild_ignore.py may not be an effective test on all OSes.
sigchild_ignore = support.findfile("sigchild_ignore.py",
@@ -1543,4 +1562,4 @@
support.reap_children()
if __name__ == "__main__":
- test_main()
+ unittest.main()
diff --git a/Lib/webbrowser.py b/Lib/webbrowser.py
--- a/Lib/webbrowser.py
+++ b/Lib/webbrowser.py
@@ -228,15 +228,9 @@
else:
# for TTY browsers, we need stdin/out
inout = None
- # if possible, put browser in separate process group, so
- # keyboard interrupts don't affect browser as well as Python
- setsid = getattr(os, 'setsid', None)
- if not setsid:
- setsid = getattr(os, 'setpgrp', None)
-
p = subprocess.Popen(cmdline, close_fds=True, stdin=inout,
stdout=(self.redirect_stdout and inout or None),
- stderr=inout, preexec_fn=setsid)
+ stderr=inout, start_new_session=True)
if remote:
# wait five secons. If the subprocess is not finished, the
# remote invocation has (hopefully) started a new instance.
diff --git a/Misc/ACKS b/Misc/ACKS
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -100,6 +100,7 @@
Forest Bond
Gawain Bolton
Gregory Bond
+Matias Bordese
Jurjen Bos
Peter Bosch
Eric Bouck
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -68,6 +68,9 @@
Library
-------
+- Issue #11289: `smtp.SMTP` class becomes a context manager so it can be used
+ in a `with` statement. Contributed by Giampaolo Rodola.
+
- Issue #11554: Fixed support for Japanese codecs; previously the body output
encoding was not done if euc-jp or shift-jis was specified as the charset.
diff --git a/Modules/_posixsubprocess.c b/Modules/_posixsubprocess.c
--- a/Modules/_posixsubprocess.c
+++ b/Modules/_posixsubprocess.c
@@ -99,10 +99,10 @@
if (p2cread > 2) {
POSIX_CALL(close(p2cread));
}
- if (c2pwrite > 2) {
+ if (c2pwrite > 2 && c2pwrite != p2cread) {
POSIX_CALL(close(c2pwrite));
}
- if (errwrite != c2pwrite && errwrite > 2) {
+ if (errwrite != c2pwrite && errwrite != p2cread && errwrite > 2) {
POSIX_CALL(close(errwrite));
}
--
Repository URL: http://hg.python.org/cpython
More information about the Python-checkins
mailing list