[Python-checkins] cpython (merge 3.3 -> 3.3): merge

christian.heimes python-checkins at python.org
Sun Sep 30 15:51:54 CEST 2012


http://hg.python.org/cpython/rev/3d10897fef9b
changeset:   79326:3d10897fef9b
branch:      3.3
parent:      79323:29506c7db353
parent:      79321:6347fb67239a
user:        Christian Heimes <christian at cheimes.de>
date:        Sun Sep 30 15:51:39 2012 +0200
summary:
  merge

files:
  Doc/library/subprocess.rst            |    8 +-
  Doc/tools/sphinxext/indexsidebar.html |    2 +-
  Doc/tools/sphinxext/layout.html       |   17 +
  Doc/tools/sphinxext/pyspecific.py     |   40 ++++
  Doc/using/windows.rst                 |    2 +
  Doc/whatsnew/3.3.rst                  |   55 ++++++-
  Doc/whatsnew/index.rst                |    8 +
  Doc/whatsnew/news.rst                 |   14 +
  Lib/bz2.py                            |   81 ++++++--
  Lib/test/test_subprocess.py           |  123 ++++++++++---
  Misc/NEWS                             |  111 ++++++++++++-
  Modules/_decimal/tests/bench.py       |    9 +-
  12 files changed, 404 insertions(+), 66 deletions(-)


diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst
--- a/Doc/library/subprocess.rst
+++ b/Doc/library/subprocess.rst
@@ -484,10 +484,10 @@
    .. 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
--- 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
--- 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
--- a/Doc/tools/sphinxext/pyspecific.py
+++ b/Doc/tools/sphinxext/pyspecific.py
@@ -145,6 +145,45 @@
         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 @@
     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
--- a/Doc/using/windows.rst
+++ b/Doc/using/windows.rst
@@ -132,6 +132,8 @@
       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
--- a/Doc/whatsnew/3.3.rst
+++ b/Doc/whatsnew/3.3.rst
@@ -51,7 +51,7 @@
 
 .. seealso::
 
-    :pep:`398` - Python 3.2 Release Schedule
+    :pep:`398` - Python 3.3 Release Schedule
 
 
 Summary -- Release highlights
@@ -289,6 +289,43 @@
       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 @@
   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
--- a/Doc/whatsnew/index.rst
+++ b/Doc/whatsnew/index.rst
@@ -23,3 +23,11 @@
    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
--- /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
--- a/Lib/bz2.py
+++ b/Lib/bz2.py
@@ -79,7 +79,8 @@
             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 @@
                     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 @@
 
     # 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 @@
                 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 @@
         """
         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 @@
         """
         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 @@
         # 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 @@
             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 @@
         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 @@
                 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
--- 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 @@
         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 @@
     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 @@
         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
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -10,13 +10,117 @@
 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 @@
 - 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
--- a/Modules/_decimal/tests/bench.py
+++ b/Modules/_decimal/tests/bench.py
@@ -18,8 +18,13 @@
 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

-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list