summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Heimes <christian@cheimes.de>2012-09-30 13:51:39 (GMT)
committerChristian Heimes <christian@cheimes.de>2012-09-30 13:51:39 (GMT)
commit5c9a5895d4357ad33c42f6d996142ae3fb591ad9 (patch)
tree78a81a898fdb26a9c5119b437f3bf995b8afd15c
parent72c9946718004a13c895cc54a2b82e9a50fd4ef3 (diff)
parent2cac28b37ef1dfdfc90481cad780c1555c713b04 (diff)
downloadcpython-5c9a5895d4357ad33c42f6d996142ae3fb591ad9.zip
cpython-5c9a5895d4357ad33c42f6d996142ae3fb591ad9.tar.gz
cpython-5c9a5895d4357ad33c42f6d996142ae3fb591ad9.tar.bz2
merge
-rw-r--r--Doc/library/subprocess.rst8
-rw-r--r--Doc/tools/sphinxext/indexsidebar.html2
-rw-r--r--Doc/tools/sphinxext/layout.html17
-rw-r--r--Doc/tools/sphinxext/pyspecific.py40
-rw-r--r--Doc/using/windows.rst2
-rw-r--r--Doc/whatsnew/3.3.rst55
-rw-r--r--Doc/whatsnew/index.rst8
-rw-r--r--Doc/whatsnew/news.rst14
-rw-r--r--Lib/bz2.py81
-rw-r--r--Lib/test/test_subprocess.py123
-rw-r--r--Misc/NEWS111
-rw-r--r--Modules/_decimal/tests/bench.py9
12 files changed, 404 insertions, 66 deletions
diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst
index 042f8f4..3ecdf4b 100644
--- a/Doc/library/subprocess.rst
+++ b/Doc/library/subprocess.rst
@@ -484,10 +484,10 @@ functions.
.. versionadded:: 3.2
The *pass_fds* parameter was added.
- If *cwd* is not ``None``, the child's current directory will be changed to *cwd*
- before it is executed. Note that this directory is not considered when
- searching the executable, so you can't specify the program's path relative to
- *cwd*.
+ If *cwd* is not ``None``, the function changes the working directory to
+ *cwd* before executing the child. In particular, the function looks for
+ *executable* (or for the first item in *args*) relative to *cwd* if the
+ executable path is a relative path.
If *restore_signals* is True (the default) all signals that Python has set to
SIG_IGN are restored to SIG_DFL in the child process before the exec.
diff --git a/Doc/tools/sphinxext/indexsidebar.html b/Doc/tools/sphinxext/indexsidebar.html
index 2018011..a0ec32f 100644
--- a/Doc/tools/sphinxext/indexsidebar.html
+++ b/Doc/tools/sphinxext/indexsidebar.html
@@ -3,7 +3,7 @@
<h3>Docs for other versions</h3>
<ul>
<li><a href="http://docs.python.org/2.7/">Python 2.7 (stable)</a></li>
- <li><a href="http://docs.python.org/3.2/">Python 3.2 (stable)</a></li>
+ <li><a href="http://docs.python.org/3.4/">Python 3.4 (in development)</a></li>
<li><a href="http://www.python.org/doc/versions/">Old versions</a></li>
</ul>
diff --git a/Doc/tools/sphinxext/layout.html b/Doc/tools/sphinxext/layout.html
index db4a386..df728aa 100644
--- a/Doc/tools/sphinxext/layout.html
+++ b/Doc/tools/sphinxext/layout.html
@@ -8,6 +8,23 @@
{% block extrahead %}
<link rel="shortcut icon" type="image/png" href="{{ pathto('_static/py.png', 1) }}" />
{% if not embedded %}<script type="text/javascript" src="{{ pathto('_static/copybutton.js', 1) }}"></script>{% endif %}
+ {% if pagename == 'whatsnew/news' %}
+ <script type="text/javascript">
+ function dofilter() {
+ var el = document.getElementById('searchbox');
+ var string = el.value.toLowerCase();
+ var litags = document.getElementsByTagName('li')
+ for (var idx = 0; idx < litags.length; idx++) {
+ var li = litags[idx];
+ if (li.innerHTML.toLowerCase().indexOf(string) >= 0) {
+ li.style.display = '';
+ } else {
+ li.style.display = 'none';
+ }
+ }
+ }
+ </script>
+ {% endif %}
{{ super() }}
{% endblock %}
{% block footer %}
diff --git a/Doc/tools/sphinxext/pyspecific.py b/Doc/tools/sphinxext/pyspecific.py
index 9fa2d2a..9304461 100644
--- a/Doc/tools/sphinxext/pyspecific.py
+++ b/Doc/tools/sphinxext/pyspecific.py
@@ -145,6 +145,45 @@ class DeprecatedRemoved(Directive):
return ret
+# Support for including Misc/NEWS
+
+import re
+import codecs
+from docutils.statemachine import string2lines
+from sphinx.util.nodes import nested_parse_with_titles
+
+issue_re = re.compile('Issue #([0-9]+)')
+
+class MiscNews(Directive):
+ has_content = False
+ required_arguments = 1
+ optional_arguments = 0
+ final_argument_whitespace = False
+ option_spec = {}
+
+ def run(self):
+ fname = self.arguments[0]
+ source = self.state_machine.input_lines.source(
+ self.lineno - self.state_machine.input_offset - 1)
+ source_dir = path.dirname(path.abspath(source))
+ try:
+ fp = codecs.open(path.join(source_dir, fname), encoding='utf-8')
+ try:
+ content = fp.read()
+ finally:
+ fp.close()
+ except Exception:
+ text = 'The NEWS file is not available.'
+ node = nodes.strong(text, text)
+ return [node]
+ content = issue_re.sub(r'`Issue #\1 <http://bugs.python.org/\1>`__',
+ content)
+ # remove first 3 lines as they are the main heading
+ lines = content.splitlines()[3:]
+ self.state_machine.insert_input(lines, fname)
+ return []
+
+
# Support for building "topic help" for pydoc
pydoc_topic_labels = [
@@ -276,3 +315,4 @@ def setup(app):
app.add_description_unit('2to3fixer', '2to3fixer', '%s (2to3 fixer)')
app.add_directive_to_domain('py', 'decorator', PyDecoratorFunction)
app.add_directive_to_domain('py', 'decoratormethod', PyDecoratorMethod)
+ app.add_directive('miscnews', MiscNews)
diff --git a/Doc/using/windows.rst b/Doc/using/windows.rst
index 51152df..5f01b77 100644
--- a/Doc/using/windows.rst
+++ b/Doc/using/windows.rst
@@ -132,6 +132,8 @@ Consult :command:`set /?` for details on this behaviour.
Setting Environment variables, Louis J. Farrugia
+.. _windows-path-mod:
+
Finding the Python executable
-----------------------------
diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst
index 1943a06..8d434db 100644
--- a/Doc/whatsnew/3.3.rst
+++ b/Doc/whatsnew/3.3.rst
@@ -51,7 +51,7 @@ see the :source:`Misc/NEWS` file.
.. seealso::
- :pep:`398` - Python 3.2 Release Schedule
+ :pep:`398` - Python 3.3 Release Schedule
Summary -- Release highlights
@@ -289,6 +289,43 @@ details).
and Martin von Löwis.
+.. _pep-397:
+
+PEP 397: Python Launcher for Windows
+====================================
+
+The Python 3.3 Windows installer now includes a ``py`` launcher application
+that can be used to launch Python applications in a version independent
+fashion.
+
+This launcher is invoked implicitly when double-clicking ``*.py`` files.
+If only a single Python version is installed on the system, that version
+will be used to run the file. If multiple versions are installed, the most
+recent version is used by default, but this can be overridden by including
+a Unix-style "shebang line" in the Python script.
+
+The launcher can also be used explicitly from the command line as the ``py``
+application. Running ``py`` follows the same version selection rules as
+implicitly launching scripts, but a more specific version can be selected
+by passing appropriate arguments (such as ``-3`` to request Python 3 when
+Python 2 is also installed, or ``-2.6`` to specifclly request an earlier
+Python version when a more recent version is installed).
+
+In addition to the launcher, the Windows installer now includes an
+option to add the newly installed Python to the system PATH (contributed
+by Brian Curtain in :issue:`3561`).
+
+.. seealso::
+
+ :pep:`397` - Python Launcher for Windows
+ PEP written by Mark Hammond and Martin v. Löwis; implementation by
+ Vinay Sajip.
+
+ Launcher documentation: :ref:`launcher`
+
+ Installer PATH modification: :ref:`windows-path-mod`
+
+
.. _pep-3151:
PEP 3151: Reworking the OS and IO exception hierarchy
@@ -2102,6 +2139,22 @@ Porting Python code
special case the standard import hooks so they are still supported even
though they do not provide the non-standard ``iter_modules()`` method.
+* A longstanding RFC-compliance bug (:issue:`1079`) in the parsing done by
+ :func:`email.header.decode_header` has been fixed. Code that uses the
+ standard idiom to convert encoded headers into unicode
+ (``str(make_header(decode_header(h))``) will see no change, but code that
+ looks at the individual tuples returned by decode_header will see that
+ whitespace that precedes or follows ``ASCII`` sections is now included in the
+ ``ASCII`` section. Code that builds headers using ``make_header`` should
+ also continue to work without change, since ``make_header`` continues to add
+ whitespace between ``ASCII`` and non-``ASCII`` sections if it is not already
+ present in the input strings.
+
+* :func:`email.utils.formataddr` now does the correct content transfer
+ encoding when passed non-``ASCII`` display names. Any code that depended on
+ the previous buggy behavior that preserved the non-``ASCII`` unicode in the
+ formatted output string will need to be changed.
+
Porting C code
--------------
diff --git a/Doc/whatsnew/index.rst b/Doc/whatsnew/index.rst
index c60818a..a06849b 100644
--- a/Doc/whatsnew/index.rst
+++ b/Doc/whatsnew/index.rst
@@ -23,3 +23,11 @@ anyone wishing to stay up-to-date after a new release.
2.2.rst
2.1.rst
2.0.rst
+
+The "Python News" is a HTML version of the file :source:`Misc/NEWS` which
+contains *all* nontrivial changes to Python.
+
+.. toctree::
+ :maxdepth: 1
+
+ news.rst
diff --git a/Doc/whatsnew/news.rst b/Doc/whatsnew/news.rst
new file mode 100644
index 0000000..2f81ed3
--- /dev/null
+++ b/Doc/whatsnew/news.rst
@@ -0,0 +1,14 @@
++++++++++++
+Python News
++++++++++++
+
+.. raw:: html
+
+ <p>
+ Filter entries by content:
+ <input type="text" value="" id="searchbox" style="width: 50%" onchange="dofilter()">
+ <input type="submit" value="Filter" onclick="dofilter()">
+ </p>
+
+.. miscnews:: ../../Misc/NEWS
+
diff --git a/Lib/bz2.py b/Lib/bz2.py
index a50adf7..fe4118f 100644
--- a/Lib/bz2.py
+++ b/Lib/bz2.py
@@ -79,7 +79,8 @@ class BZ2File(io.BufferedIOBase):
mode = "rb"
mode_code = _MODE_READ
self._decompressor = BZ2Decompressor()
- self._buffer = None
+ self._buffer = b""
+ self._buffer_offset = 0
elif mode in ("w", "wb"):
mode = "wb"
mode_code = _MODE_WRITE
@@ -124,7 +125,8 @@ class BZ2File(io.BufferedIOBase):
self._fp = None
self._closefp = False
self._mode = _MODE_CLOSED
- self._buffer = None
+ self._buffer = b""
+ self._buffer_offset = 0
@property
def closed(self):
@@ -174,16 +176,13 @@ class BZ2File(io.BufferedIOBase):
# Fill the readahead buffer if it is empty. Returns False on EOF.
def _fill_buffer(self):
+ if self._mode == _MODE_READ_EOF:
+ return False
# Depending on the input data, our call to the decompressor may not
# return any data. In this case, try again after reading another block.
- while True:
- if self._buffer:
- return True
-
- if self._decompressor.unused_data:
- rawblock = self._decompressor.unused_data
- else:
- rawblock = self._fp.read(_BUFFER_SIZE)
+ while self._buffer_offset == len(self._buffer):
+ rawblock = (self._decompressor.unused_data or
+ self._fp.read(_BUFFER_SIZE))
if not rawblock:
if self._decompressor.eof:
@@ -199,30 +198,48 @@ class BZ2File(io.BufferedIOBase):
self._decompressor = BZ2Decompressor()
self._buffer = self._decompressor.decompress(rawblock)
+ self._buffer_offset = 0
+ return True
# Read data until EOF.
# If return_data is false, consume the data without returning it.
def _read_all(self, return_data=True):
+ # The loop assumes that _buffer_offset is 0. Ensure that this is true.
+ self._buffer = self._buffer[self._buffer_offset:]
+ self._buffer_offset = 0
+
blocks = []
while self._fill_buffer():
if return_data:
blocks.append(self._buffer)
self._pos += len(self._buffer)
- self._buffer = None
+ self._buffer = b""
if return_data:
return b"".join(blocks)
# Read a block of up to n bytes.
# If return_data is false, consume the data without returning it.
def _read_block(self, n, return_data=True):
+ # If we have enough data buffered, return immediately.
+ end = self._buffer_offset + n
+ if end <= len(self._buffer):
+ data = self._buffer[self._buffer_offset : end]
+ self._buffer_offset = end
+ self._pos += len(data)
+ return data if return_data else None
+
+ # The loop assumes that _buffer_offset is 0. Ensure that this is true.
+ self._buffer = self._buffer[self._buffer_offset:]
+ self._buffer_offset = 0
+
blocks = []
while n > 0 and self._fill_buffer():
if n < len(self._buffer):
data = self._buffer[:n]
- self._buffer = self._buffer[n:]
+ self._buffer_offset = n
else:
data = self._buffer
- self._buffer = None
+ self._buffer = b""
if return_data:
blocks.append(data)
self._pos += len(data)
@@ -238,9 +255,9 @@ class BZ2File(io.BufferedIOBase):
"""
with self._lock:
self._check_can_read()
- if self._mode == _MODE_READ_EOF or not self._fill_buffer():
+ if not self._fill_buffer():
return b""
- return self._buffer
+ return self._buffer[self._buffer_offset:]
def read(self, size=-1):
"""Read up to size uncompressed bytes from the file.
@@ -250,7 +267,7 @@ class BZ2File(io.BufferedIOBase):
"""
with self._lock:
self._check_can_read()
- if self._mode == _MODE_READ_EOF or size == 0:
+ if size == 0:
return b""
elif size < 0:
return self._read_all()
@@ -268,15 +285,19 @@ class BZ2File(io.BufferedIOBase):
# In this case we make multiple reads, to avoid returning b"".
with self._lock:
self._check_can_read()
- if (size == 0 or self._mode == _MODE_READ_EOF or
- not self._fill_buffer()):
+ if (size == 0 or
+ # Only call _fill_buffer() if the buffer is actually empty.
+ # This gives a significant speedup if *size* is small.
+ (self._buffer_offset == len(self._buffer) and not self._fill_buffer())):
return b""
- if 0 < size < len(self._buffer):
- data = self._buffer[:size]
- self._buffer = self._buffer[size:]
+ if size > 0:
+ data = self._buffer[self._buffer_offset :
+ self._buffer_offset + size]
+ self._buffer_offset += len(data)
else:
- data = self._buffer
- self._buffer = None
+ data = self._buffer[self._buffer_offset:]
+ self._buffer = b""
+ self._buffer_offset = 0
self._pos += len(data)
return data
@@ -299,6 +320,14 @@ class BZ2File(io.BufferedIOBase):
raise TypeError("Integer argument expected")
size = size.__index__()
with self._lock:
+ # Shortcut for the common case - the whole line is in the buffer.
+ if size < 0:
+ end = self._buffer.find(b"\n", self._buffer_offset) + 1
+ if end > 0:
+ line = self._buffer[self._buffer_offset : end]
+ self._buffer_offset = end
+ self._pos += len(line)
+ return line
return io.BufferedIOBase.readline(self, size)
def readlines(self, size=-1):
@@ -345,7 +374,8 @@ class BZ2File(io.BufferedIOBase):
self._mode = _MODE_READ
self._pos = 0
self._decompressor = BZ2Decompressor()
- self._buffer = None
+ self._buffer = b""
+ self._buffer_offset = 0
def seek(self, offset, whence=0):
"""Change the file position.
@@ -385,8 +415,7 @@ class BZ2File(io.BufferedIOBase):
offset -= self._pos
# Read and discard data until we reach the desired position.
- if self._mode != _MODE_READ_EOF:
- self._read_block(offset, return_data=False)
+ self._read_block(offset, return_data=False)
return self._pos
diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py
index 2420772..24924f6 100644
--- a/Lib/test/test_subprocess.py
+++ b/Lib/test/test_subprocess.py
@@ -1,4 +1,5 @@
import unittest
+from test import script_helper
from test import support
import subprocess
import sys
@@ -191,15 +192,101 @@ class ProcessTestCase(BaseTestCase):
p.wait()
self.assertEqual(p.stderr, None)
+ # For use in the test_cwd* tests below.
+ def _normalize_cwd(self, cwd):
+ # Normalize an expected cwd (for Tru64 support).
+ # We can't use os.path.realpath since it doesn't expand Tru64 {memb}
+ # strings. See bug #1063571.
+ original_cwd = os.getcwd()
+ os.chdir(cwd)
+ cwd = os.getcwd()
+ os.chdir(original_cwd)
+ return cwd
+
+ # For use in the test_cwd* tests below.
+ def _split_python_path(self):
+ # Return normalized (python_dir, python_base).
+ python_path = os.path.realpath(sys.executable)
+ return os.path.split(python_path)
+
+ # For use in the test_cwd* tests below.
+ def _assert_cwd(self, expected_cwd, python_arg, **kwargs):
+ # Invoke Python via Popen, and assert that (1) the call succeeds,
+ # and that (2) the current working directory of the child process
+ # matches *expected_cwd*.
+ p = subprocess.Popen([python_arg, "-c",
+ "import os, sys; "
+ "sys.stdout.write(os.getcwd()); "
+ "sys.exit(47)"],
+ stdout=subprocess.PIPE,
+ **kwargs)
+ self.addCleanup(p.stdout.close)
+ p.wait()
+ self.assertEqual(47, p.returncode)
+ normcase = os.path.normcase
+ self.assertEqual(normcase(expected_cwd),
+ normcase(p.stdout.read().decode("utf-8")))
+
+ def test_cwd(self):
+ # Check that cwd changes the cwd for the child process.
+ temp_dir = tempfile.gettempdir()
+ temp_dir = self._normalize_cwd(temp_dir)
+ self._assert_cwd(temp_dir, sys.executable, cwd=temp_dir)
+
+ def test_cwd_with_relative_arg(self):
+ # Check that Popen looks for args[0] relative to cwd if args[0]
+ # is relative.
+ python_dir, python_base = self._split_python_path()
+ rel_python = os.path.join(os.curdir, python_base)
+ with support.temp_cwd() as wrong_dir:
+ # Before calling with the correct cwd, confirm that the call fails
+ # without cwd and with the wrong cwd.
+ self.assertRaises(FileNotFoundError, subprocess.Popen,
+ [rel_python])
+ self.assertRaises(FileNotFoundError, subprocess.Popen,
+ [rel_python], cwd=wrong_dir)
+ python_dir = self._normalize_cwd(python_dir)
+ self._assert_cwd(python_dir, rel_python, cwd=python_dir)
+
+ def test_cwd_with_relative_executable(self):
+ # Check that Popen looks for executable relative to cwd if executable
+ # is relative (and that executable takes precedence over args[0]).
+ python_dir, python_base = self._split_python_path()
+ rel_python = os.path.join(os.curdir, python_base)
+ doesntexist = "somethingyoudonthave"
+ with support.temp_cwd() as wrong_dir:
+ # Before calling with the correct cwd, confirm that the call fails
+ # without cwd and with the wrong cwd.
+ self.assertRaises(FileNotFoundError, subprocess.Popen,
+ [doesntexist], executable=rel_python)
+ self.assertRaises(FileNotFoundError, subprocess.Popen,
+ [doesntexist], executable=rel_python,
+ cwd=wrong_dir)
+ python_dir = self._normalize_cwd(python_dir)
+ self._assert_cwd(python_dir, doesntexist, executable=rel_python,
+ cwd=python_dir)
+
+ def test_cwd_with_absolute_arg(self):
+ # Check that Popen can find the executable when the cwd is wrong
+ # if args[0] is an absolute path.
+ python_dir, python_base = self._split_python_path()
+ abs_python = os.path.join(python_dir, python_base)
+ rel_python = os.path.join(os.curdir, python_base)
+ with script_helper.temp_dir() as wrong_dir:
+ # Before calling with an absolute path, confirm that using a
+ # relative path fails.
+ self.assertRaises(FileNotFoundError, subprocess.Popen,
+ [rel_python], cwd=wrong_dir)
+ wrong_dir = self._normalize_cwd(wrong_dir)
+ self._assert_cwd(wrong_dir, abs_python, cwd=wrong_dir)
+
@unittest.skipIf(sys.base_prefix != sys.prefix,
'Test is not venv-compatible')
def test_executable_with_cwd(self):
- python_dir = os.path.dirname(os.path.realpath(sys.executable))
- p = subprocess.Popen(["somethingyoudonthave", "-c",
- "import sys; sys.exit(47)"],
- executable=sys.executable, cwd=python_dir)
- p.wait()
- self.assertEqual(p.returncode, 47)
+ python_dir, python_base = self._split_python_path()
+ python_dir = self._normalize_cwd(python_dir)
+ self._assert_cwd(python_dir, "somethingyoudonthave",
+ executable=sys.executable, cwd=python_dir)
@unittest.skipIf(sys.base_prefix != sys.prefix,
'Test is not venv-compatible')
@@ -208,11 +295,7 @@ class ProcessTestCase(BaseTestCase):
def test_executable_without_cwd(self):
# For a normal installation, it should work without 'cwd'
# argument. For test runs in the build directory, see #7774.
- p = subprocess.Popen(["somethingyoudonthave", "-c",
- "import sys; sys.exit(47)"],
- executable=sys.executable)
- p.wait()
- self.assertEqual(p.returncode, 47)
+ self._assert_cwd('', "somethingyoudonthave", executable=sys.executable)
def test_stdin_pipe(self):
# stdin redirection
@@ -369,24 +452,6 @@ class ProcessTestCase(BaseTestCase):
p.wait()
self.assertEqual(p.stdin, None)
- def test_cwd(self):
- tmpdir = tempfile.gettempdir()
- # We cannot use os.path.realpath to canonicalize the path,
- # since it doesn't expand Tru64 {memb} strings. See bug 1063571.
- cwd = os.getcwd()
- os.chdir(tmpdir)
- tmpdir = os.getcwd()
- os.chdir(cwd)
- p = subprocess.Popen([sys.executable, "-c",
- 'import sys,os;'
- 'sys.stdout.write(os.getcwd())'],
- stdout=subprocess.PIPE,
- cwd=tmpdir)
- self.addCleanup(p.stdout.close)
- normcase = os.path.normcase
- self.assertEqual(normcase(p.stdout.read().decode("utf-8")),
- normcase(tmpdir))
-
def test_env(self):
newenv = os.environ.copy()
newenv["FRUIT"] = "orange"
diff --git a/Misc/NEWS b/Misc/NEWS
index 245cf1a..794363e 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -10,13 +10,117 @@ What's New in Python 3.3.1?
Core and Builtins
-----------------
+- Issue #15379: Fix passing of non-BMP characters as integers for the charmap
+ decoder (already working as unicode strings). Patch by Serhiy Storchaka.
+
+- Issue #15144: Fix possible integer overflow when handling pointers as
+ integer values, by using Py_uintptr_t instead of size_t. Patch by
+ Serhiy Storchaka.
+
+- Issue #15965: Explicitly cast AT_FDCWD as (int). Required on Solaris 10
+ (which defines AT_FDCWD as 0xffd19553), harmless on other platforms.
+
+- Issue #15839: Convert SystemErrors in super() to RuntimeErrors.
+
+- Issue #15846: Fix SystemError which happened when using ast.parse in an
+ exception handler on code with syntax errors.
+
+- Issue #15801: Make sure mappings passed to '%' formatting are actually
+ subscriptable.
+
+
Library
-------
+- Issue #16034: Fix performance regressions in the new BZ2File implementation.
+ Initial patch by Serhiy Storchaka.
+
- Issue #15756: subprocess.poll() now properly handles errno.ECHILD to
return a returncode of 0 when the child has already exited or cannot
be waited on.
+- Issue #15323: improve failure message of Mock.assert_called_once_with
+
+- Issue #16064: unittest -m claims executable is "python", not "python3"
+
+- Issue #12376: Pass on parameters in TextTestResult.__init__ super call
+
+- Issue #15222: Insert blank line after each message in mbox mailboxes
+
+- Issue #16013: Fix CSV Reader parsing issue with ending quote characters.
+ Patch by Serhiy Storchaka.
+
+- Issue #15421: Fix an OverflowError in Calendar.itermonthdates() after
+ datetime.MAXYEAR. Patch by Cédric Krier.
+
+- Issue #15970: xml.etree.ElementTree now serializes correctly the empty HTML
+ elements 'meta' and 'param'.
+
+- Issue #15842: The SocketIO.{readable,writable,seekable} methods now
+ raise ValueError when the file-like object is closed. Patch by Alessandro
+ Moura.
+
+- Issue #15876: Fix a refleak in the curses module: window.encoding.
+
+- Issue #15881: Fixed atexit hook in multiprocessing. Original patch
+ by Chris McDonough.
+
+- Issue #15841: The readable(), writable() and seekable() methods of BytesIO
+ and StringIO objects now raise ValueError when the object has been closed.
+ Patch by Alessandro Moura.
+
+- Issue #15447: Use subprocess.DEVNULL in webbrowser, instead of opening
+ os.devnull explicitly and leaving it open.
+
+- Issue #15509: webbrowser.UnixBrowser no longer passes empty arguments to
+ Popen when %action substitutions produce empty strings.
+
+- Issues #12776, #11839: call argparse type function (specified by add_argument)
+ only once. Before, the type function was called twice in the case where the
+ default was specified and the argument was given as well. This was especially
+ problematic for the FileType type, as a default file would always be opened,
+ even if a file argument was specified on the command line.
+
+- Issue #15906: Fix a regression in argparse caused by the preceding change,
+ when action='append', type='str' and default=[].
+
+Tests
+-----
+
+- Issue #15304: Fix warning message when os.chdir() fails inside
+ test.support.temp_cwd(). Patch by Chris Jerdonek.
+
+- Issue #15802: Fix test logic in TestMaildir.test_create_tmp. Patch
+ by Serhiy Storchaka.
+
+- Issue #15557: Added a test suite for the webbrowser module, thanks
+ to Anton Barkovsky.
+
+Build
+-----
+
+- Issue #15819: Make sure we can build Python out-of-tree from a readonly
+ source directory. (Somewhat related to Issue #9860.)
+
+Documentation
+-------------
+
+- Issue #15533: Clarify docs and add tests for subprocess.Popen()'s cwd
+ argument.
+
+- Issue #16036: Improve documentation of built-in int()'s signature and
+ arguments.
+
+- Issue #15935: Clarification of argparse docs, re: add_argument() type and
+ default arguments. Patch contributed by Chris Jerdonek.
+
+- Issue #11964: Document a change in v3.2 to the behavior of the indent
+ parameter of json encoding operations.
+
+Tools/Demos
+-----------
+
+
What's New in Python 3.3.0?
===========================
@@ -560,9 +664,10 @@ Tools/Demos
- Issue #12605: The gdb hooks for debugging CPython (within Tools/gdb) have been
enhanced to show information on more C frames relevant to CPython within the
"py-bt" and "py-bt-full" commands:
- * C frames that are waiting on the GIL
- * C frames that are garbage-collecting
- * C frames that are due to the invocation of a PyCFunction
+
+ * C frames that are waiting on the GIL
+ * C frames that are garbage-collecting
+ * C frames that are due to the invocation of a PyCFunction
Documentation
-------------
diff --git a/Modules/_decimal/tests/bench.py b/Modules/_decimal/tests/bench.py
index 7ab6b44..7e4a210 100644
--- a/Modules/_decimal/tests/bench.py
+++ b/Modules/_decimal/tests/bench.py
@@ -18,8 +18,13 @@ except ImportError:
C = import_fresh_module('decimal', fresh=['_decimal'])
P = import_fresh_module('decimal', blocked=['_decimal'])
-
-# Pi function from the decimal.py documentation
+#
+# NOTE: This is the pi function from the decimal documentation, modified
+# for benchmarking purposes. Since floats do not have a context, the higher
+# intermediate precision from the original is NOT used, so the modified
+# algorithm only gives an approximation to the correctly rounded result.
+# For serious use, refer to the documentation or the appropriate literature.
+#
def pi_float():
"""native float"""
lasts, t, s, n, na, d, da = 0, 3.0, 3, 1, 0, 0, 24