Merge 3.2.1 release clone changes into main 3.2 branch after 3.2.1rc2 release.
diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst
index 7367674..32ae724 100644
--- a/Doc/library/sqlite3.rst
+++ b/Doc/library/sqlite3.rst
@@ -599,43 +599,43 @@
Let's assume we initialize a table as in the example given above::
- conn = sqlite3.connect(":memory:")
- c = conn.cursor()
- c.execute('''create table stocks
- (date text, trans text, symbol text,
- qty real, price real)''')
- c.execute("""insert into stocks
- values ('2006-01-05','BUY','RHAT',100,35.14)""")
- conn.commit()
- c.close()
+ conn = sqlite3.connect(":memory:")
+ c = conn.cursor()
+ c.execute('''create table stocks
+ (date text, trans text, symbol text,
+ qty real, price real)''')
+ c.execute("""insert into stocks
+ values ('2006-01-05','BUY','RHAT',100,35.14)""")
+ conn.commit()
+ c.close()
Now we plug :class:`Row` in::
- >>> conn.row_factory = sqlite3.Row
- >>> c = conn.cursor()
- >>> c.execute('select * from stocks')
- <sqlite3.Cursor object at 0x7f4e7dd8fa80>
- >>> r = c.fetchone()
- >>> type(r)
- <class 'sqlite3.Row'>
- >>> tuple(r)
- ('2006-01-05', 'BUY', 'RHAT', 100.0, 35.14)
- >>> len(r)
- 5
- >>> r[2]
- 'RHAT'
- >>> r.keys()
- ['date', 'trans', 'symbol', 'qty', 'price']
- >>> r['qty']
- 100.0
- >>> for member in r:
- ... print(member)
- ...
- 2006-01-05
- BUY
- RHAT
- 100.0
- 35.14
+ >>> conn.row_factory = sqlite3.Row
+ >>> c = conn.cursor()
+ >>> c.execute('select * from stocks')
+ <sqlite3.Cursor object at 0x7f4e7dd8fa80>
+ >>> r = c.fetchone()
+ >>> type(r)
+ <class 'sqlite3.Row'>
+ >>> tuple(r)
+ ('2006-01-05', 'BUY', 'RHAT', 100.0, 35.14)
+ >>> len(r)
+ 5
+ >>> r[2]
+ 'RHAT'
+ >>> r.keys()
+ ['date', 'trans', 'symbol', 'qty', 'price']
+ >>> r['qty']
+ 100.0
+ >>> for member in r:
+ ... print(member)
+ ...
+ 2006-01-05
+ BUY
+ RHAT
+ 100.0
+ 35.14
.. _sqlite3-types:
@@ -886,6 +886,7 @@
.. rubric:: Footnotes
.. [#f1] The sqlite3 module is not built with loadable extension support by
- default, because some platforms (notably Mac OS X) have SQLite libraries which
- are compiled without this feature. To get loadable extension support, you must
- pass --enable-loadable-sqlite-extensions to configure.
+ default, because some platforms (notably Mac OS X) have SQLite
+ libraries which are compiled without this feature. To get loadable
+ extension support, you must pass --enable-loadable-sqlite-extensions to
+ configure.
diff --git a/Lib/glob.py b/Lib/glob.py
index c5f5f69..36d493d 100644
--- a/Lib/glob.py
+++ b/Lib/glob.py
@@ -1,6 +1,5 @@
"""Filename globbing utility."""
-import sys
import os
import re
import fnmatch
diff --git a/Lib/idlelib/PyShell.py b/Lib/idlelib/PyShell.py
index 06c8bba..834805e 100644
--- a/Lib/idlelib/PyShell.py
+++ b/Lib/idlelib/PyShell.py
@@ -59,7 +59,7 @@
file = warning_stream
try:
file.write(warnings.formatwarning(message, category, filename,
- lineno, file=file, line=line))
+ lineno, line=line))
except IOError:
pass ## file (probably __stderr__) is invalid, warning dropped.
warnings.showwarning = idle_showwarning
diff --git a/Lib/pydoc.py b/Lib/pydoc.py
index 1619446..2533226 100755
--- a/Lib/pydoc.py
+++ b/Lib/pydoc.py
@@ -256,20 +256,18 @@
def importfile(path):
"""Import a Python source file or compiled file given its path."""
magic = imp.get_magic()
- file = open(path, 'r')
- if file.read(len(magic)) == magic:
- kind = imp.PY_COMPILED
- else:
- kind = imp.PY_SOURCE
- file.close()
- filename = os.path.basename(path)
- name, ext = os.path.splitext(filename)
- file = open(path, 'r')
- try:
- module = imp.load_module(name, file, path, (ext, 'r', kind))
- except:
- raise ErrorDuringImport(path, sys.exc_info())
- file.close()
+ with open(path, 'rb') as file:
+ if file.read(len(magic)) == magic:
+ kind = imp.PY_COMPILED
+ else:
+ kind = imp.PY_SOURCE
+ file.seek(0)
+ filename = os.path.basename(path)
+ name, ext = os.path.splitext(filename)
+ try:
+ module = imp.load_module(name, file, path, (ext, 'r', kind))
+ except:
+ raise ErrorDuringImport(path, sys.exc_info())
return module
def safeimport(path, forceload=0, cache={}):
diff --git a/Lib/runpy.py b/Lib/runpy.py
index 4738df3..31e5e55 100644
--- a/Lib/runpy.py
+++ b/Lib/runpy.py
@@ -226,7 +226,7 @@
code = read_code(f)
if code is None:
# That didn't work, so try it as normal source code
- with open(fname, "rU") as f:
+ with open(fname, "rb") as f:
code = compile(f.read(), fname, 'exec')
return code
diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py
index 76f4249..46ddc82 100644
--- a/Lib/test/test_exceptions.py
+++ b/Lib/test/test_exceptions.py
@@ -566,6 +566,33 @@
del g
self.assertEqual(sys.exc_info()[0], TypeError)
+ def test_generator_leaking2(self):
+ # See issue 12475.
+ def g():
+ yield
+ try:
+ raise RuntimeError
+ except RuntimeError:
+ it = g()
+ next(it)
+ try:
+ next(it)
+ except StopIteration:
+ pass
+ self.assertEqual(sys.exc_info(), (None, None, None))
+
+ def test_generator_doesnt_retain_old_exc(self):
+ def g():
+ self.assertIsInstance(sys.exc_info()[1], RuntimeError)
+ yield
+ self.assertEqual(sys.exc_info(), (None, None, None))
+ it = g()
+ try:
+ raise RuntimeError
+ except RuntimeError:
+ next(it)
+ self.assertRaises(StopIteration, next, it)
+
def test_generator_finalizing_and_exc_info(self):
# See #7173
def simple_gen():
diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py
index 707b7cb..cfd4583 100644
--- a/Lib/test/test_io.py
+++ b/Lib/test/test_io.py
@@ -2651,6 +2651,8 @@
1/0
@unittest.skipUnless(threading, 'Threading required for this test.')
+ @unittest.skipIf(sys.platform in ('freebsd5', 'freebsd6', 'freebsd7'),
+ 'issue #12429: skip test on FreeBSD <= 7')
def check_interrupted_write(self, item, bytes, **fdopen_kwargs):
"""Check that a partial write, when it gets interrupted, properly
invokes the signal handler, and bubbles up the exception raised
diff --git a/Lib/test/test_runpy.py b/Lib/test/test_runpy.py
index ad3ab39..7ffb6af 100644
--- a/Lib/test/test_runpy.py
+++ b/Lib/test/test_runpy.py
@@ -405,6 +405,16 @@
msg = "recursion depth exceeded"
self.assertRaisesRegex(RuntimeError, msg, run_path, zip_name)
+ def test_encoding(self):
+ with temp_dir() as script_dir:
+ filename = os.path.join(script_dir, 'script.py')
+ with open(filename, 'w', encoding='latin1') as f:
+ f.write("""
+#coding:latin1
+"non-ASCII: h\xe9"
+""")
+ result = run_path(filename)
+ self.assertEqual(result['__doc__'], "non-ASCII: h\xe9")
def test_main():
diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py
index 475a26b..e2310e2 100644
--- a/Lib/test/test_shutil.py
+++ b/Lib/test/test_shutil.py
@@ -427,7 +427,7 @@
self.assertEqual(os.stat(file1).st_mode, os.stat(file2).st_mode)
@unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
- @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.utime')
+ @unittest.skipUnless(hasattr(os, 'utime'), 'requires os.utime')
def test_copy2(self):
# Ensure that the copied file exists and has the same mode and
# modification time bits.
diff --git a/Lib/test/test_signal.py b/Lib/test/test_signal.py
index ede6545..8df1bf0 100644
--- a/Lib/test/test_signal.py
+++ b/Lib/test/test_signal.py
@@ -11,7 +11,7 @@
import unittest
from test import support
from contextlib import closing
-from test.script_helper import spawn_python
+from test.script_helper import assert_python_ok, spawn_python
if sys.platform in ('os2', 'riscos'):
raise unittest.SkipTest("Can't test signal on %s" % sys.platform)
@@ -233,49 +233,80 @@
@unittest.skipIf(sys.platform == "win32", "Not valid on Windows")
class WakeupSignalTests(unittest.TestCase):
- TIMEOUT_FULL = 10
- TIMEOUT_HALF = 5
+ def check_wakeup(self, test_body):
+ # use a subprocess to have only one thread and to not change signal
+ # handling of the parent process
+ code = """if 1:
+ import fcntl
+ import os
+ import signal
+
+ def handler(signum, frame):
+ pass
+
+ {}
+
+ signal.signal(signal.SIGALRM, handler)
+ read, write = os.pipe()
+ flags = fcntl.fcntl(write, fcntl.F_GETFL, 0)
+ flags = flags | os.O_NONBLOCK
+ fcntl.fcntl(write, fcntl.F_SETFL, flags)
+ signal.set_wakeup_fd(write)
+
+ test()
+
+ os.close(read)
+ os.close(write)
+ """.format(test_body)
+
+ assert_python_ok('-c', code)
def test_wakeup_fd_early(self):
- import select
+ self.check_wakeup("""def test():
+ import select
+ import time
- signal.alarm(1)
- before_time = time.time()
- # We attempt to get a signal during the sleep,
- # before select is called
- time.sleep(self.TIMEOUT_FULL)
- mid_time = time.time()
- self.assertTrue(mid_time - before_time < self.TIMEOUT_HALF)
- select.select([self.read], [], [], self.TIMEOUT_FULL)
- after_time = time.time()
- self.assertTrue(after_time - mid_time < self.TIMEOUT_HALF)
+ TIMEOUT_FULL = 10
+ TIMEOUT_HALF = 5
+
+ signal.alarm(1)
+ before_time = time.time()
+ # We attempt to get a signal during the sleep,
+ # before select is called
+ time.sleep(TIMEOUT_FULL)
+ mid_time = time.time()
+ dt = mid_time - before_time
+ if dt >= TIMEOUT_HALF:
+ raise Exception("%s >= %s" % (dt, TIMEOUT_HALF))
+ select.select([read], [], [], TIMEOUT_FULL)
+ after_time = time.time()
+ dt = after_time - mid_time
+ if dt >= TIMEOUT_HALF:
+ raise Exception("%s >= %s" % (dt, TIMEOUT_HALF))
+ """)
def test_wakeup_fd_during(self):
- import select
+ self.check_wakeup("""def test():
+ import select
+ import time
- signal.alarm(1)
- before_time = time.time()
- # We attempt to get a signal during the select call
- self.assertRaises(select.error, select.select,
- [self.read], [], [], self.TIMEOUT_FULL)
- after_time = time.time()
- self.assertTrue(after_time - before_time < self.TIMEOUT_HALF)
+ TIMEOUT_FULL = 10
+ TIMEOUT_HALF = 5
- def setUp(self):
- import fcntl
-
- self.alrm = signal.signal(signal.SIGALRM, lambda x,y:None)
- self.read, self.write = os.pipe()
- flags = fcntl.fcntl(self.write, fcntl.F_GETFL, 0)
- flags = flags | os.O_NONBLOCK
- fcntl.fcntl(self.write, fcntl.F_SETFL, flags)
- self.old_wakeup = signal.set_wakeup_fd(self.write)
-
- def tearDown(self):
- signal.set_wakeup_fd(self.old_wakeup)
- os.close(self.read)
- os.close(self.write)
- signal.signal(signal.SIGALRM, self.alrm)
+ signal.alarm(1)
+ before_time = time.time()
+ # We attempt to get a signal during the select call
+ try:
+ select.select([read], [], [], TIMEOUT_FULL)
+ except select.error:
+ pass
+ else:
+ raise Exception("select.error not raised")
+ after_time = time.time()
+ dt = after_time - before_time
+ if dt >= TIMEOUT_HALF:
+ raise Exception("%s >= %s" % (dt, TIMEOUT_HALF))
+ """)
@unittest.skipIf(sys.platform == "win32", "Not valid on Windows")
class SiginterruptTest(unittest.TestCase):
diff --git a/Lib/test/test_tk.py b/Lib/test/test_tk.py
index ab979fa..f993c53 100644
--- a/Lib/test/test_tk.py
+++ b/Lib/test/test_tk.py
@@ -2,15 +2,11 @@
# Skip test if _tkinter wasn't built.
support.import_module('_tkinter')
-import tkinter
-from tkinter.test import runtktests
-import unittest
+# Skip test if tk cannot be initialized.
+from tkinter.test.support import check_tk_availability
+check_tk_availability()
-try:
- tkinter.Button()
-except tkinter.TclError as msg:
- # assuming tk is not available
- raise unittest.SkipTest("tk not available: %s" % msg)
+from tkinter.test import runtktests
def test_main(enable_gui=False):
if enable_gui:
diff --git a/Lib/test/test_ttk_guionly.py b/Lib/test/test_ttk_guionly.py
index bff4fc1..b8c1a4c 100644
--- a/Lib/test/test_ttk_guionly.py
+++ b/Lib/test/test_ttk_guionly.py
@@ -5,6 +5,10 @@
# Skip this test if _tkinter wasn't built.
support.import_module('_tkinter')
+# Skip test if tk cannot be initialized.
+from tkinter.test.support import check_tk_availability
+check_tk_availability()
+
from _tkinter import TclError
from tkinter import ttk
from tkinter.test import runtktests
diff --git a/Lib/test/test_unicode.py b/Lib/test/test_unicode.py
index 97be587..885e740 100644
--- a/Lib/test/test_unicode.py
+++ b/Lib/test/test_unicode.py
@@ -788,6 +788,7 @@
self.assertEqual('%c' % '\U00021483', '\U00021483')
self.assertRaises(TypeError, "%c".__mod__, "aa")
self.assertRaises(ValueError, "%.1\u1032f".__mod__, (1.0/3))
+ self.assertRaises(TypeError, "%i".__mod__, "aa")
# formatting jobs delegated from the string implementation:
self.assertEqual('...%(foo)s...' % {'foo':"abc"}, '...abc...')
diff --git a/Lib/tkinter/test/support.py b/Lib/tkinter/test/support.py
index 97212fb..20bd412 100644
--- a/Lib/tkinter/test/support.py
+++ b/Lib/tkinter/test/support.py
@@ -1,6 +1,42 @@
+import subprocess
+import sys
+from test import support
import tkinter
+import unittest
+
+_tk_available = None
+
+def check_tk_availability():
+ """Check that Tk is installed and available."""
+ global _tk_available
+
+ if _tk_available is not None:
+ return
+
+ if sys.platform == 'darwin':
+ # The Aqua Tk implementations on OS X can abort the process if
+ # being called in an environment where a window server connection
+ # cannot be made, for instance when invoked by a buildbot or ssh
+ # process not running under the same user id as the current console
+ # user. Instead, try to initialize Tk under a subprocess.
+ p = subprocess.Popen(
+ [sys.executable, '-c', 'import tkinter; tkinter.Button()'],
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ stderr = support.strip_python_stderr(p.communicate()[1])
+ if stderr or p.returncode:
+ raise unittest.SkipTest("tk cannot be initialized: %s" % stderr)
+ else:
+ try:
+ tkinter.Button()
+ except tkinter.TclError as msg:
+ # assuming tk is not available
+ raise unittest.SkipTest("tk not available: %s" % msg)
+
+ _tk_available = True
+ return
def get_tk_root():
+ check_tk_availability() # raise exception if tk unavailable
try:
root = tkinter._default_root
except AttributeError:
diff --git a/Lib/xml/dom/pulldom.py b/Lib/xml/dom/pulldom.py
index 81a36b0..d5ac8b2 100644
--- a/Lib/xml/dom/pulldom.py
+++ b/Lib/xml/dom/pulldom.py
@@ -326,7 +326,7 @@
if bufsize is None:
bufsize = default_bufsize
if isinstance(stream_or_string, str):
- stream = open(stream_or_string)
+ stream = open(stream_or_string, 'rb')
else:
stream = stream_or_string
if not parser:
diff --git a/Misc/NEWS b/Misc/NEWS
index 1518bd1..67485b3 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -2,6 +2,51 @@
Python News
+++++++++++
+What's New in Python 3.2.2?
+===========================
+
+*Release date: XX-XX-2011*
+
+Core and Builtins
+-----------------
+
+- When a generator yields, do not retain the caller's exception state on the
+ generator.
+
+- Issue #12475: Prevent generators from leaking their exception state into the
+ caller's frame as they return for the last time.
+
+Library
+-------
+
+- Issue #12467: warnings: fix a race condition if a warning is emitted at
+ shutdown, if globals()['__file__'] is None.
+
+- Issue #12451: pydoc: importfile() now opens the Python script in binary mode,
+ instead of text mode using the locale encoding, to avoid encoding issues.
+
+- Issue #12451: runpy: run_path() now opens the Python script in binary mode,
+ instead of text mode using the locale encoding, to support other encodings
+ than UTF-8 (scripts using the coding cookie).
+
+- Issue #12451: xml.dom.pulldom: parse() now opens files in binary mode instead
+ of the text mode (using the locale encoding) to avoid encoding issues.
+
+C-API
+-----
+
+Tests
+-----
+
+- Issue #12469: Run "wakeup" signal tests in subprocess to run the test in a
+ fresh process with only one thread and to not change signal handling of the
+ parent process.
+
+- Issue #8716: Avoid crashes caused by Aqua Tk on OSX when attempting to run
+ test_tk or test_ttk_guionly under a username that is not currently logged
+ in to the console windowserver (as may be the case under buildbot or ssh).
+
+
What's New in Python 3.2.1?
===========================
diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c
index 7a70a5e..03807a4 100644
--- a/Objects/unicodeobject.c
+++ b/Objects/unicodeobject.c
@@ -9689,8 +9689,6 @@
case 'o':
case 'x':
case 'X':
- if (c == 'i')
- c = 'd';
isnumok = 0;
if (PyNumber_Check(v)) {
PyObject *iobj=NULL;
@@ -9705,7 +9703,7 @@
if (iobj!=NULL) {
if (PyLong_Check(iobj)) {
isnumok = 1;
- temp = formatlong(iobj, flags, prec, c);
+ temp = formatlong(iobj, flags, prec, (c == 'i'? 'd': c));
Py_DECREF(iobj);
if (!temp)
goto onError;
diff --git a/Python/_warnings.c b/Python/_warnings.c
index 07fd683..99f6071 100644
--- a/Python/_warnings.c
+++ b/Python/_warnings.c
@@ -517,6 +517,7 @@
}
else {
const char *module_str = _PyUnicode_AsString(*module);
+ Py_XDECREF(*filename);
if (module_str == NULL)
goto handle_error;
if (strcmp(module_str, "__main__") == 0) {
diff --git a/Python/ceval.c b/Python/ceval.c
index 705ed41..5c3bb83 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -1145,6 +1145,23 @@
f->f_exc_traceback = tmp; \
}
+#define RESTORE_AND_CLEAR_EXC_STATE() \
+ { \
+ PyObject *type, *value, *tb; \
+ type = tstate->exc_type; \
+ value = tstate->exc_value; \
+ tb = tstate->exc_traceback; \
+ tstate->exc_type = f->f_exc_type; \
+ tstate->exc_value = f->f_exc_value; \
+ tstate->exc_traceback = f->f_exc_traceback; \
+ f->f_exc_type = NULL; \
+ f->f_exc_value = NULL; \
+ f->f_exc_traceback = NULL; \
+ Py_XDECREF(type); \
+ Py_XDECREF(value); \
+ Py_XDECREF(tb); \
+ }
+
/* Start of code */
if (f == NULL)
@@ -1881,10 +1898,6 @@
retval = POP();
f->f_stacktop = stack_pointer;
why = WHY_YIELD;
- /* Put aside the current exception state and restore
- that of the calling frame. This only serves when
- "yield" is used inside an except handler. */
- SWAP_EXC_STATE();
goto fast_yield;
TARGET(POP_EXCEPT)
@@ -3021,6 +3034,26 @@
retval = NULL;
fast_yield:
+ if (co->co_flags & CO_GENERATOR && (why == WHY_YIELD || why == WHY_RETURN)) {
+ /* The purpose of this block is to put aside the generator's exception
+ state and restore that of the calling frame. If the current
+ exception state is from the caller, we clear the exception values
+ on the generator frame, so they are not swapped back in latter. The
+ origin of the current exception state is determined by checking for
+ except handler blocks, which we must be in iff a new exception
+ state came into existence in this frame. (An uncaught exception
+ would have why == WHY_EXCEPTION, and we wouldn't be here). */
+ int i;
+ for (i = 0; i < f->f_iblock; i++)
+ if (f->f_blockstack[i].b_type == EXCEPT_HANDLER)
+ break;
+ if (i == f->f_iblock)
+ /* We did not create this exception. */
+ RESTORE_AND_CLEAR_EXC_STATE()
+ else
+ SWAP_EXC_STATE()
+ }
+
if (tstate->use_tracing) {
if (tstate->c_tracefunc) {
if (why == WHY_RETURN || why == WHY_YIELD) {