This commit is contained in:
Christian Heimes 2012-09-30 15:51:39 +02:00
commit 5c9a5895d4
12 changed files with 404 additions and 66 deletions

View File

@ -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.

View File

@ -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>

View File

@ -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 %}

View File

@ -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)

View File

@ -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
-----------------------------

View File

@ -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
--------------

View File

@ -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

14
Doc/whatsnew/news.rst Normal file
View File

@ -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

View File

@ -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

View File

@ -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"

111
Misc/NEWS
View File

@ -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
-------------

View File

@ -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