Mailing List Archive

cpython (merge default -> default): Merge
http://hg.python.org/cpython/rev/65ac469d30e6
changeset: 74251:65ac469d30e6
parent: 74249:ace54f5e75d7
parent: 74247:4c243c8ecd10
user: Antoine Pitrou <solipsis@pitrou.net>
date: Tue Jan 03 22:50:16 2012 +0100
summary:
Merge

files:
Doc/library/socketserver.rst | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)


diff --git a/Doc/library/socketserver.rst b/Doc/library/socketserver.rst
--- a/Doc/library/socketserver.rst
+++ b/Doc/library/socketserver.rst
@@ -153,8 +153,8 @@

.. method:: BaseServer.serve_forever(poll_interval=0.5)

- Handle requests until an explicit :meth:`shutdown` request. Polls for
- shutdown every *poll_interval* seconds. It also calls
+ Handle requests until an explicit :meth:`shutdown` request.
+ Poll for shutdown every *poll_interval* seconds. Ignores :attr:`self.timeout`. It also calls
:meth:`service_actions` which may be used by a subclass or Mixin to provide
various cleanup actions. For e.g. ForkingMixin class uses
:meth:`service_actions` to cleanup the zombie child processes.
@@ -172,7 +172,7 @@

.. method:: BaseServer.shutdown()

- Tells the :meth:`serve_forever` loop to stop and waits until it does.
+ Tell the :meth:`serve_forever` loop to stop and waits until it does.


.. attribute:: BaseServer.address_family

--
Repository URL: http://hg.python.org/cpython
cpython (merge default -> default): Merge [ In reply to ]
http://hg.python.org/cpython/rev/ec95169055ab
changeset: 74375:ec95169055ab
parent: 74374:e6b0d9d209f2
parent: 74371:e2f11c6305ae
user: Terry Jan Reedy <tjreedy@udel.edu>
date: Fri Jan 13 23:47:41 2012 -0500
summary:
Merge

files:
Doc/library/exceptions.rst | 3 +++
Doc/reference/expressions.rst | 5 ++++-
Doc/reference/simple_stmts.rst | 5 ++++-
Doc/whatsnew/3.3.rst | 1 +
4 files changed, 12 insertions(+), 2 deletions(-)


diff --git a/Doc/library/exceptions.rst b/Doc/library/exceptions.rst
--- a/Doc/library/exceptions.rst
+++ b/Doc/library/exceptions.rst
@@ -261,6 +261,9 @@
raised, and the value returned by the function is used as the
:attr:`value` parameter to the constructor of the exception.

+ .. versionchanged:: 3.3
+ Added ``value`` attribute and the ability for generator functions to
+ use it to return a value.

.. exception:: SyntaxError

diff --git a/Doc/reference/expressions.rst b/Doc/reference/expressions.rst
--- a/Doc/reference/expressions.rst
+++ b/Doc/reference/expressions.rst
@@ -355,7 +355,7 @@
garbage collected), the generator-iterator's :meth:`close` method will be
called, allowing any pending :keyword:`finally` clauses to execute.

-When ``yield from expression`` is used, it treats the supplied expression as
+When ``yield from <expr>`` is used, it treats the supplied expression as
a subiterator. All values produced by that subiterator are passed directly
to the caller of the current generator's methods. Any values passed in with
:meth:`send` and any exceptions passed in with :meth:`throw` are passed to
@@ -369,6 +369,9 @@
:exc:`StopIteration`, or automatically when the sub-iterator is a generator
(by returning a value from the sub-generator).

+ .. versionchanged:: 3.3
+ Added ``yield from <expr>`` to delegate control flow to a subiterator
+
The parentheses can be omitted when the :keyword:`yield` expression is the
sole expression on the right hand side of an assignment statement.

diff --git a/Doc/reference/simple_stmts.rst b/Doc/reference/simple_stmts.rst
--- a/Doc/reference/simple_stmts.rst
+++ b/Doc/reference/simple_stmts.rst
@@ -470,10 +470,13 @@
garbage collected), the generator-iterator's :meth:`close` method will be
called, allowing any pending :keyword:`finally` clauses to execute.

-When ``yield from expression`` is used, it treats the supplied expression as
+When ``yield from <expr>`` is used, it treats the supplied expression as
a subiterator, producing values from it until the underlying iterator is
exhausted.

+ .. versionchanged:: 3.3
+ Added ``yield from <expr>`` to delegate control flow to a subiterator
+
For full details of :keyword:`yield` semantics, refer to the :ref:`yieldexpr`
section.

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
@@ -224,6 +224,7 @@
how they might be accessible from the global scope.

Example with (non-bound) methods::
+
>>> class C:
... def meth(self):
... pass

--
Repository URL: http://hg.python.org/cpython
cpython (merge default -> default): Merge [ In reply to ]
http://hg.python.org/cpython/rev/12de1ad1cee8
changeset: 74478:12de1ad1cee8
parent: 74477:26b6732ecb87
parent: 74476:1de276420470
user: Antoine Pitrou <solipsis@pitrou.net>
date: Wed Jan 18 02:05:38 2012 +0100
summary:
Merge

files:
Doc/library/time.rst | 12 ++++++
Doc/library/webbrowser.rst | 7 ++-
Doc/whatsnew/3.3.rst | 12 +++--
Lib/bz2.py | 8 +++-
Lib/test/test_bz2.py | 7 +++
Lib/test/test_time.py | 7 +++
Misc/NEWS | 5 ++
Modules/timemodule.c | 47 ++++++++++++++++++++++++++
8 files changed, 96 insertions(+), 9 deletions(-)


diff --git a/Doc/library/time.rst b/Doc/library/time.rst
--- a/Doc/library/time.rst
+++ b/Doc/library/time.rst
@@ -183,6 +183,18 @@

.. versionadded:: 3.3

+.. function:: wallclock()
+
+ .. index::
+ single: Wallclock
+ single: benchmarking
+
+ Return the current time in fractions of a second to the system's best ability.
+ Use this when the most accurate representation of wall-clock is required, i.e.
+ when "processor time" is inappropriate. The reference point of the returned
+ value is undefined so only the difference of consecutive calls is valid.
+
+ .. versionadded: 3.3

.. function:: ctime([secs])

diff --git a/Doc/library/webbrowser.rst b/Doc/library/webbrowser.rst
--- a/Doc/library/webbrowser.rst
+++ b/Doc/library/webbrowser.rst
@@ -164,12 +164,15 @@
(4)
Only on Mac OS X platform.

+.. versionadded:: 3.3
+ Support for Chrome/Chromium has been added.
+
Here are some simple examples::

- url = 'http://www.python.org/'
+ url = 'http://docs.python.org/'

# Open URL in a new tab, if a browser window is already open.
- webbrowser.open_new_tab(url + 'doc/')
+ webbrowser.open_new_tab(url)

# Open URL in new window, raising the window if possible.
webbrowser.open_new(url)
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
@@ -396,12 +396,14 @@
time
----

-* The :mod:`time` module has new :func:`~time.clock_getres` and
- :func:`~time.clock_gettime` functions and ``CLOCK_xxx`` constants.
- :func:`~time.clock_gettime` can be used with :data:`time.CLOCK_MONOTONIC` to
- get a monotonic clock.
+The :mod:`time` module has new functions:

- (Contributed by Victor Stinner in :issue:`10278`)
+* :func:`~time.clock_getres` and :func:`~time.clock_gettime` functions and
+ ``CLOCK_xxx`` constants. :func:`~time.clock_gettime` can be used with
+ :data:`time.CLOCK_MONOTONIC` to get a monotonic clock.
+* :func:`~time.wallclock`: monotonic clock.
+
+(Contributed by Victor Stinner in :issue:`10278`)


ftplib
diff --git a/Lib/bz2.py b/Lib/bz2.py
--- a/Lib/bz2.py
+++ b/Lib/bz2.py
@@ -10,9 +10,13 @@
__author__ = "Nadeem Vawda <nadeem.vawda@gmail.com>"

import io
-import threading
import warnings

+try:
+ from threading import RLock
+except ImportError:
+ from dummy_threading import RLock
+
from _bz2 import BZ2Compressor, BZ2Decompressor


@@ -53,7 +57,7 @@
"""
# This lock must be recursive, so that BufferedIOBase's
# readline(), readlines() and writelines() don't deadlock.
- self._lock = threading.RLock()
+ self._lock = RLock()
self._fp = None
self._closefp = False
self._mode = _MODE_CLOSED
diff --git a/Lib/test/test_bz2.py b/Lib/test/test_bz2.py
--- a/Lib/test/test_bz2.py
+++ b/Lib/test/test_bz2.py
@@ -463,6 +463,13 @@
for t in threads:
t.join()

+ def testWithoutThreading(self):
+ bz2 = support.import_fresh_module("bz2", blocked=("threading",))
+ with bz2.BZ2File(self.filename, "wb") as f:
+ f.write(b"abc")
+ with bz2.BZ2File(self.filename, "rb") as f:
+ self.assertEqual(f.read(), b"abc")
+
def testMixedIterationAndReads(self):
self.createTempFile()
linelen = len(self.TEXT_LINES[0])
diff --git a/Lib/test/test_time.py b/Lib/test/test_time.py
--- a/Lib/test/test_time.py
+++ b/Lib/test/test_time.py
@@ -332,6 +332,13 @@
self.assertEqual(time.strftime('%Z', tt), tzname)


+ def test_wallclock(self):
+ t0 = time.wallclock()
+ time.sleep(0.1)
+ t1 = time.wallclock()
+ t = t1 - t0
+ self.assertAlmostEqual(t, 0.1, places=2)
+
class TestLocale(unittest.TestCase):
def setUp(self):
self.oldloc = locale.setlocale(locale.LC_ALL)
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -447,6 +447,11 @@
Library
-------

+- Issue #10278: Add time.wallclock() function, monotonic clock.
+
+- Issue #13809: Fix regression where bz2 module wouldn't work when threads are
+ disabled. Original patch by Amaury Forgeot d'Arc.
+
- Issue #13589: Fix some serialization primitives in the aifc module.
Patch by Oleg Plakhotnyuk.

diff --git a/Modules/timemodule.c b/Modules/timemodule.c
--- a/Modules/timemodule.c
+++ b/Modules/timemodule.c
@@ -737,6 +737,52 @@
should not be relied on.");
#endif /* HAVE_WORKING_TZSET */

+static PyObject *
+time_wallclock(PyObject *self, PyObject *unused)
+{
+#if defined(MS_WINDOWS) && !defined(__BORLANDC__)
+ return time_clock(self, NULL);
+#elif defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
+ static int clk_index = 0;
+ clockid_t clk_ids[] = {
+#ifdef CLOCK_MONOTONIC_RAW
+ CLOCK_MONOTONIC_RAW,
+#endif
+ CLOCK_MONOTONIC
+#ifdef CLOCK_REALTIME
+ /* On Linux, CLOCK_REALTIME uses the same clock than gettimeofday(),
+ but clock_gettime() has a nanosecond resolution. */
+ , CLOCK_REALTIME
+#endif
+ };
+ int ret;
+ struct timespec tp;
+
+ while (0 <= clk_index) {
+ clockid_t clk_id = clk_ids[clk_index];
+ ret = clock_gettime(clk_id, &tp);
+ if (ret == 0)
+ return PyFloat_FromDouble(tp.tv_sec + tp.tv_nsec * 1e-9);
+
+ clk_index++;
+ if (Py_ARRAY_LENGTH(clk_ids) <= clk_index)
+ clk_index = -1;
+ }
+ return time_time(self, NULL);
+#else
+ return time_time(self, NULL);
+#endif
+}
+
+PyDoc_STRVAR(wallclock_doc,
+"wallclock() -> float\n\
+\n\
+Return the current time in fractions of a second to the system's best\n\
+ability. Use this when the most accurate representation of wall-clock is\n\
+required, i.e. when \"processor time\" is inappropriate. The reference point\n\
+of the returned value is undefined so only the difference of consecutive\n\
+calls is valid.");
+
static void
PyInit_timezone(PyObject *m) {
/* This code moved from PyInit_time wholesale to allow calling it from
@@ -872,6 +918,7 @@
#ifdef HAVE_WORKING_TZSET
{"tzset", time_tzset, METH_NOARGS, tzset_doc},
#endif
+ {"wallclock", time_wallclock, METH_NOARGS, wallclock_doc},
{NULL, NULL} /* sentinel */
};


--
Repository URL: http://hg.python.org/cpython
cpython (merge default -> default): Merge [ In reply to ]
http://hg.python.org/cpython/rev/93075fb1360a
changeset: 74631:93075fb1360a
parent: 74629:d2cf8a34ddf9
parent: 74630:7d8f016784cd
user: Brett Cannon <brett@python.org>
date: Thu Jan 26 08:58:19 2012 -0500
summary:
Merge

files:
Lib/importlib/__init__.py | 43 ++-------
Lib/importlib/_bootstrap.py | 39 ++++++++-
Lib/importlib/abc.py | 4 +-
Lib/importlib/test/source/test_abc_loader.py | 8 +-
4 files changed, 52 insertions(+), 42 deletions(-)


diff --git a/Lib/importlib/__init__.py b/Lib/importlib/__init__.py
--- a/Lib/importlib/__init__.py
+++ b/Lib/importlib/__init__.py
@@ -26,8 +26,15 @@
import re
import tokenize

+# To simplify imports in test code
+_w_long = _bootstrap._w_long
+_r_long = _bootstrap._r_long
+
+
# Bootstrap help #####################################################

+# TODO: Expose from import.c, else handle encode/decode as _os.environ returns
+# bytes.
def _case_ok(directory, check):
"""Check if the directory contains something matching 'check'.

@@ -36,37 +43,13 @@
"""
if 'PYTHONCASEOK' in os.environ:
return True
- elif check in os.listdir(directory if directory else os.getcwd()):
+ if not directory:
+ directory = os.getcwd()
+ if check in os.listdir(directory):
return True
return False

-
-def _w_long(x):
- """Convert a 32-bit integer to little-endian.
-
- XXX Temporary until marshal's long functions are exposed.
-
- """
- x = int(x)
- int_bytes = []
- int_bytes.append(x & 0xFF)
- int_bytes.append((x >> 8) & 0xFF)
- int_bytes.append((x >> 16) & 0xFF)
- int_bytes.append((x >> 24) & 0xFF)
- return bytearray(int_bytes)
-
-
-def _r_long(int_bytes):
- """Convert 4 bytes in little-endian to an integer.
-
- XXX Temporary until marshal's long function are exposed.
-
- """
- x = int_bytes[0]
- x |= int_bytes[1] << 8
- x |= int_bytes[2] << 16
- x |= int_bytes[3] << 24
- return x
+_bootstrap._case_ok = _case_ok


# Required built-in modules.
@@ -94,10 +77,6 @@
# For os.path.join replacement; pull from Include/osdefs.h:SEP .
_bootstrap.path_sep = sep

-_bootstrap._case_ok = _case_ok
-marshal._w_long = _w_long
-marshal._r_long = _r_long
-

# Public API #########################################################

diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py
--- a/Lib/importlib/_bootstrap.py
+++ b/Lib/importlib/_bootstrap.py
@@ -18,6 +18,37 @@

# Bootstrap-related code ######################################################

+# TODO: Expose from marshal
+def _w_long(x):
+ """Convert a 32-bit integer to little-endian.
+
+ XXX Temporary until marshal's long functions are exposed.
+
+ """
+ x = int(x)
+ int_bytes = []
+ int_bytes.append(x & 0xFF)
+ int_bytes.append((x >> 8) & 0xFF)
+ int_bytes.append((x >> 16) & 0xFF)
+ int_bytes.append((x >> 24) & 0xFF)
+ return bytearray(int_bytes)
+
+
+# TODO: Expose from marshal
+def _r_long(int_bytes):
+ """Convert 4 bytes in little-endian to an integer.
+
+ XXX Temporary until marshal's long function are exposed.
+
+ """
+ x = int_bytes[0]
+ x |= int_bytes[1] << 8
+ x |= int_bytes[2] << 16
+ x |= int_bytes[3] << 24
+ return x
+
+
+
# XXX Could also expose Modules/getpath.c:joinpath()
def _path_join(*args):
"""Replacement for os.path.join."""
@@ -353,14 +384,14 @@
except KeyError:
pass
else:
- if marshal._r_long(raw_timestamp) != source_mtime:
+ if _r_long(raw_timestamp) != source_mtime:
raise ImportError("bytecode is stale for {}".format(fullname))
try:
source_size = source_stats['size'] & 0xFFFFFFFF
except KeyError:
pass
else:
- if marshal._r_long(raw_size) != source_size:
+ if _r_long(raw_size) != source_size:
raise ImportError("bytecode is stale for {}".format(fullname))
# Can't return the code object as errors from marshal loading need to
# propagate even when source is available.
@@ -472,8 +503,8 @@
# their own cached file format, this block of code will most likely
# throw an exception.
data = bytearray(imp.get_magic())
- data.extend(marshal._w_long(source_mtime))
- data.extend(marshal._w_long(len(source_bytes)))
+ data.extend(_w_long(source_mtime))
+ data.extend(_w_long(len(source_bytes)))
data.extend(marshal.dumps(code_object))
try:
self.set_data(bytecode_path, data)
diff --git a/Lib/importlib/abc.py b/Lib/importlib/abc.py
--- a/Lib/importlib/abc.py
+++ b/Lib/importlib/abc.py
@@ -260,7 +260,7 @@
raw_timestamp = data[4:8]
if len(raw_timestamp) < 4:
raise EOFError("bad timestamp in {}".format(fullname))
- pyc_timestamp = marshal._r_long(raw_timestamp)
+ pyc_timestamp = _bootstrap._r_long(raw_timestamp)
bytecode = data[8:]
# Verify that the magic number is valid.
if imp.get_magic() != magic:
@@ -292,7 +292,7 @@
# Generate bytecode and write it out.
if not sys.dont_write_bytecode:
data = bytearray(imp.get_magic())
- data.extend(marshal._w_long(source_timestamp))
+ data.extend(_bootstrap._w_long(source_timestamp))
data.extend(marshal.dumps(code_object))
self.write_bytecode(fullname, data)
return code_object
diff --git a/Lib/importlib/test/source/test_abc_loader.py b/Lib/importlib/test/source/test_abc_loader.py
--- a/Lib/importlib/test/source/test_abc_loader.py
+++ b/Lib/importlib/test/source/test_abc_loader.py
@@ -42,8 +42,8 @@
self.bytecode_path = imp.cache_from_source(self.path)
self.source_size = len(self.source)
data = bytearray(magic)
- data.extend(marshal._w_long(self.source_mtime))
- data.extend(marshal._w_long(self.source_size))
+ data.extend(importlib._w_long(self.source_mtime))
+ data.extend(importlib._w_long(self.source_size))
code_object = compile(self.source, self.path, 'exec',
dont_inherit=True)
data.extend(marshal.dumps(code_object))
@@ -658,8 +658,8 @@
if bytecode_written:
self.assertIn(self.cached, self.loader.written)
data = bytearray(imp.get_magic())
- data.extend(marshal._w_long(self.loader.source_mtime))
- data.extend(marshal._w_long(self.loader.source_size))
+ data.extend(importlib._w_long(self.loader.source_mtime))
+ data.extend(importlib._w_long(self.loader.source_size))
data.extend(marshal.dumps(code_object))
self.assertEqual(self.loader.written[self.cached], bytes(data))


--
Repository URL: http://hg.python.org/cpython
cpython (merge default -> default): Merge [ In reply to ]
http://hg.python.org/cpython/rev/dc3de15b43db
changeset: 74638:dc3de15b43db
parent: 74636:0f00010c88f0
parent: 74634:9ee4a104e33d
user: Brett Cannon <brett@python.org>
date: Thu Jan 26 18:34:34 2012 -0500
summary:
Merge

files:
Doc/library/ctypes.rst | 4 -
Lib/collections/__init__.py | 2 +-
Lib/test/test_time.py | 15 +++
Misc/NEWS | 7 +
Modules/_ctypes/_ctypes.c | 2 +-
Modules/timemodule.c | 114 +++++++++++++----------
Python/import.c | 6 -
7 files changed, 86 insertions(+), 64 deletions(-)


diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst
--- a/Doc/library/ctypes.rst
+++ b/Doc/library/ctypes.rst
@@ -1823,8 +1823,6 @@
termination character. An integer can be passed as second argument which allows
to specify the size of the array if the length of the bytes should not be used.

- If the first parameter is a string, it is converted into a bytes object
- according to ctypes conversion rules.


.. function:: create_unicode_buffer(init_or_size, size=None)
@@ -1841,8 +1839,6 @@
allows to specify the size of the array if the length of the string should not
be used.

- If the first parameter is a bytes object, it is converted into an unicode string
- according to ctypes conversion rules.


.. function:: DllCanUnloadNow()
diff --git a/Lib/collections/__init__.py b/Lib/collections/__init__.py
--- a/Lib/collections/__init__.py
+++ b/Lib/collections/__init__.py
@@ -34,7 +34,7 @@
# The circular doubly linked list starts and ends with a sentinel element.
# The sentinel element never gets deleted (this simplifies the algorithm).
# The sentinel is in self.__hardroot with a weakref proxy in self.__root.
- # The prev/next links are weakref proxies (to prevent circular references).
+ # The prev links are weakref proxies (to prevent circular references).
# Individual links are kept alive by the hard reference in self.__map.
# Those hard references disappear when a key is deleted from an OrderedDict.

diff --git a/Lib/test/test_time.py b/Lib/test/test_time.py
--- a/Lib/test/test_time.py
+++ b/Lib/test/test_time.py
@@ -343,6 +343,21 @@
dt = t2 - t1
self.assertAlmostEqual(dt, 0.1, delta=0.2)

+ def test_localtime_failure(self):
+ # Issue #13847: check for localtime() failure
+ invalid_time_t = 2**60
+ try:
+ time.localtime(invalid_time_t)
+ except ValueError as err:
+ if str(err) == "timestamp out of range for platform time_t":
+ self.skipTest("need 64-bit time_t")
+ else:
+ raise
+ except OSError:
+ pass
+ self.assertRaises(OSError, time.localtime, invalid_time_t)
+ self.assertRaises(OSError, time.gmtime, invalid_time_t)
+ self.assertRaises(OSError, time.ctime, invalid_time_t)

class TestLocale(unittest.TestCase):
def setUp(self):
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -461,6 +461,10 @@
Library
-------

+- Issue #13847: time.localtime() and time.gmtime() now raise an OSError instead
+ of ValueError on failure. time.ctime() and time.asctime() now raises an
+ OSError if localtime() failed.
+
- Issue #13862: Fix spurious failure in test_zlib due to runtime/compile time
minor versions not matching.

@@ -1837,6 +1841,9 @@
Extension Modules
-----------------

+- Issue #13840: The error message produced by ctypes.create_string_buffer
+ when given a Unicode string has been fixed.
+
- Issue #9975: socket: Fix incorrect use of flowinfo and scope_id. Patch by
Vilmos Nebehaj.

diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c
--- a/Modules/_ctypes/_ctypes.c
+++ b/Modules/_ctypes/_ctypes.c
@@ -1096,7 +1096,7 @@

if (!PyBytes_Check(value)) {
PyErr_Format(PyExc_TypeError,
- "str/bytes expected instead of %s instance",
+ "bytes expected instead of %s instance",
Py_TYPE(value)->tp_name);
return -1;
} else
diff --git a/Modules/timemodule.c b/Modules/timemodule.c
--- a/Modules/timemodule.c
+++ b/Modules/timemodule.c
@@ -247,55 +247,53 @@
return v;
}

-static PyObject *
-time_convert(double when, struct tm * (*function)(const time_t *))
-{
- struct tm *p;
- time_t whent = _PyTime_DoubleToTimet(when);
-
- if (whent == (time_t)-1 && PyErr_Occurred())
- return NULL;
- errno = 0;
- p = function(&whent);
- if (p == NULL) {
-#ifdef EINVAL
- if (errno == 0)
- errno = EINVAL;
-#endif
- return PyErr_SetFromErrno(PyExc_ValueError);
- }
- return tmtotuple(p);
-}
-
/* Parse arg tuple that can contain an optional float-or-None value;
format needs to be "|O:name".
Returns non-zero on success (parallels PyArg_ParseTuple).
*/
static int
-parse_time_double_args(PyObject *args, char *format, double *pwhen)
+parse_time_t_args(PyObject *args, char *format, time_t *pwhen)
{
PyObject *ot = NULL;
+ time_t whent;

if (!PyArg_ParseTuple(args, format, &ot))
return 0;
- if (ot == NULL || ot == Py_None)
- *pwhen = floattime();
+ if (ot == NULL || ot == Py_None) {
+ whent = time(NULL);
+ }
else {
- double when = PyFloat_AsDouble(ot);
+ double d = PyFloat_AsDouble(ot);
if (PyErr_Occurred())
return 0;
- *pwhen = when;
+ whent = _PyTime_DoubleToTimet(d);
+ if (whent == (time_t)-1 && PyErr_Occurred())
+ return 0;
}
+ *pwhen = whent;
return 1;
}

static PyObject *
time_gmtime(PyObject *self, PyObject *args)
{
- double when;
- if (!parse_time_double_args(args, "|O:gmtime", &when))
+ time_t when;
+ struct tm buf, *local;
+
+ if (!parse_time_t_args(args, "|O:gmtime", &when))
return NULL;
- return time_convert(when, gmtime);
+
+ errno = 0;
+ local = gmtime(&when);
+ if (local == NULL) {
+#ifdef EINVAL
+ if (errno == 0)
+ errno = EINVAL;
+#endif
+ return PyErr_SetFromErrno(PyExc_OSError);
+ }
+ buf = *local;
+ return tmtotuple(&buf);
}

PyDoc_STRVAR(gmtime_doc,
@@ -305,13 +303,37 @@
Convert seconds since the Epoch to a time tuple expressing UTC (a.k.a.\n\
GMT). When 'seconds' is not passed in, convert the current time instead.");

+static int
+pylocaltime(time_t *timep, struct tm *result)
+{
+ struct tm *local;
+
+ assert (timep != NULL);
+ local = localtime(timep);
+ if (local == NULL) {
+ /* unconvertible time */
+#ifdef EINVAL
+ if (errno == 0)
+ errno = EINVAL;
+#endif
+ PyErr_SetFromErrno(PyExc_OSError);
+ return -1;
+ }
+ *result = *local;
+ return 0;
+}
+
static PyObject *
time_localtime(PyObject *self, PyObject *args)
{
- double when;
- if (!parse_time_double_args(args, "|O:localtime", &when))
+ time_t when;
+ struct tm buf;
+
+ if (!parse_time_t_args(args, "|O:localtime", &when))
return NULL;
- return time_convert(when, localtime);
+ if (pylocaltime(&when, &buf) == 1)
+ return NULL;
+ return tmtotuple(&buf);
}

PyDoc_STRVAR(localtime_doc,
@@ -462,7 +484,8 @@

if (tup == NULL) {
time_t tt = time(NULL);
- buf = *localtime(&tt);
+ if (pylocaltime(&tt, &buf) == -1)
+ return NULL;
}
else if (!gettmarg(tup, &buf) || !checktm(&buf))
return NULL;
@@ -627,7 +650,9 @@
return NULL;
if (tup == NULL) {
time_t tt = time(NULL);
- buf = *localtime(&tt);
+ if (pylocaltime(&tt, &buf) == -1)
+ return NULL;
+
} else if (!gettmarg(tup, &buf) || !checktm(&buf))
return NULL;
return _asctime(&buf);
@@ -643,28 +668,13 @@
static PyObject *
time_ctime(PyObject *self, PyObject *args)
{
- PyObject *ot = NULL;
time_t tt;
- struct tm *timeptr;
-
- if (!PyArg_UnpackTuple(args, "ctime", 0, 1, &ot))
+ struct tm buf;
+ if (!parse_time_t_args(args, "|O:ctime", &tt))
return NULL;
- if (ot == NULL || ot == Py_None)
- tt = time(NULL);
- else {
- double dt = PyFloat_AsDouble(ot);
- if (PyErr_Occurred())
- return NULL;
- tt = _PyTime_DoubleToTimet(dt);
- if (tt == (time_t)-1 && PyErr_Occurred())
- return NULL;
- }
- timeptr = localtime(&tt);
- if (timeptr == NULL) {
- PyErr_SetString(PyExc_ValueError, "unconvertible time");
+ if (pylocaltime(&tt, &buf) == -1)
return NULL;
- }
- return _asctime(timeptr);
+ return _asctime(&buf);
}

PyDoc_STRVAR(ctime_doc,
diff --git a/Python/import.c b/Python/import.c
--- a/Python/import.c
+++ b/Python/import.c
@@ -2052,12 +2052,6 @@
if (p_loader != NULL)
*p_loader = NULL;

- if (PyUnicode_GET_LENGTH(name) > MAXPATHLEN) {
- PyErr_SetString(PyExc_OverflowError,
- "module name is too long");
- return NULL;
- }
-
/* sys.meta_path import hook */
if (p_loader != NULL) {
_Py_IDENTIFIER(find_module);

--
Repository URL: http://hg.python.org/cpython
cpython (merge default -> default): Merge [ In reply to ]
http://hg.python.org/cpython/rev/082eea3fc9bc
changeset: 74644:082eea3fc9bc
parent: 74643:ecf4a7bb8807
parent: 74642:856f0864437a
user: Brett Cannon <brett@python.org>
date: Thu Jan 26 19:09:44 2012 -0500
summary:
Merge

files:
Lib/test/test_time.py | 27 +++++++++++++--------
Misc/NEWS | 3 +-
Modules/timemodule.c | 38 ++++++++++++++++++++++--------
3 files changed, 45 insertions(+), 23 deletions(-)


diff --git a/Lib/test/test_time.py b/Lib/test/test_time.py
--- a/Lib/test/test_time.py
+++ b/Lib/test/test_time.py
@@ -309,7 +309,7 @@
for t in (-2, -1, 0, 1):
try:
tt = time.localtime(t)
- except (OverflowError, ValueError):
+ except (OverflowError, OSError):
pass
else:
self.assertEqual(time.mktime(tt), t)
@@ -345,16 +345,21 @@

def test_localtime_failure(self):
# Issue #13847: check for localtime() failure
- invalid_time_t = 2**60
- try:
- time.localtime(invalid_time_t)
- except ValueError as err:
- if str(err) == "timestamp out of range for platform time_t":
- self.skipTest("need 64-bit time_t")
- else:
- raise
- except OSError:
- pass
+ invalid_time_t = None
+ for time_t in (-1, 2**30, 2**33, 2**60):
+ try:
+ time.localtime(time_t)
+ except ValueError as err:
+ if str(err) == "timestamp out of range for platform time_t":
+ self.skipTest("need 64-bit time_t")
+ else:
+ raise
+ except OSError:
+ invalid_time_t = time_t
+ break
+ if invalid_time_t is None:
+ self.skipTest("unable to find an invalid time_t value")
+
self.assertRaises(OSError, time.localtime, invalid_time_t)
self.assertRaises(OSError, time.gmtime, invalid_time_t)
self.assertRaises(OSError, time.ctime, invalid_time_t)
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -463,7 +463,8 @@

- Issue #13847: time.localtime() and time.gmtime() now raise an OSError instead
of ValueError on failure. time.ctime() and time.asctime() now raises an
- OSError if localtime() failed.
+ OSError if localtime() failed. time.clock() now raises a RuntimeError if the
+ processor time used is not available or its value cannot be represented

- Issue #13862: Fix spurious failure in test_zlib due to runtime/compile time
minor versions not matching.
diff --git a/Modules/timemodule.c b/Modules/timemodule.c
--- a/Modules/timemodule.c
+++ b/Modules/timemodule.c
@@ -62,6 +62,31 @@
Return the current time in seconds since the Epoch.\n\
Fractions of a second may be present if the system clock provides them.");

+#if defined(HAVE_CLOCK)
+
+#ifndef CLOCKS_PER_SEC
+#ifdef CLK_TCK
+#define CLOCKS_PER_SEC CLK_TCK
+#else
+#define CLOCKS_PER_SEC 1000000
+#endif
+#endif
+
+static PyObject *
+pyclock(void)
+{
+ clock_t value;
+ value = clock();
+ if (value == (clock_t)-1) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "the processor time used is not available "
+ "or its value cannot be represented");
+ return NULL;
+ }
+ return PyFloat_FromDouble((double)value / CLOCKS_PER_SEC);
+}
+#endif /* HAVE_CLOCK */
+
#if defined(MS_WINDOWS) && !defined(__BORLANDC__)
/* Win32 has better clock replacement; we have our own version, due to Mark
Hammond and Tim Peters */
@@ -79,8 +104,7 @@
if (!QueryPerformanceFrequency(&freq) || freq.QuadPart == 0) {
/* Unlikely to happen - this works on all intel
machines at least! Revert to clock() */
- return PyFloat_FromDouble(((double)clock()) /
- CLOCKS_PER_SEC);
+ return pyclock();
}
divisor = (double)freq.QuadPart;
}
@@ -91,18 +115,10 @@

#elif defined(HAVE_CLOCK)

-#ifndef CLOCKS_PER_SEC
-#ifdef CLK_TCK
-#define CLOCKS_PER_SEC CLK_TCK
-#else
-#define CLOCKS_PER_SEC 1000000
-#endif
-#endif
-
static PyObject *
time_clock(PyObject *self, PyObject *unused)
{
- return PyFloat_FromDouble(((double)clock()) / CLOCKS_PER_SEC);
+ return pyclock();
}
#endif /* HAVE_CLOCK */


--
Repository URL: http://hg.python.org/cpython
cpython (merge default -> default): Merge [ In reply to ]
http://hg.python.org/cpython/rev/06d47538af89
changeset: 74700:06d47538af89
parent: 74699:2d0ff4d82b14
parent: 74697:bf31815548c9
user: Brett Cannon <brett@python.org>
date: Tue Jan 31 14:58:07 2012 -0500
summary:
Merge

files:
Lib/idlelib/PyShell.py | 19 +++++++++++++------
Lib/idlelib/ScriptBinding.py | 5 ++---
Misc/ACKS | 1 +
Misc/NEWS | 3 +++
Modules/zipimport.c | 9 +++++----
5 files changed, 24 insertions(+), 13 deletions(-)


diff --git a/Lib/idlelib/PyShell.py b/Lib/idlelib/PyShell.py
--- a/Lib/idlelib/PyShell.py
+++ b/Lib/idlelib/PyShell.py
@@ -411,11 +411,11 @@
self.rpcclt.register("flist", self.tkconsole.flist)
self.rpcclt.register("linecache", linecache)
self.rpcclt.register("interp", self)
- self.transfer_path()
+ self.transfer_path(with_cwd=True)
self.poll_subprocess()
return self.rpcclt

- def restart_subprocess(self):
+ def restart_subprocess(self, with_cwd=False):
if self.restarting:
return self.rpcclt
self.restarting = True
@@ -439,7 +439,7 @@
except socket.timeout as err:
self.display_no_subprocess_error()
return None
- self.transfer_path()
+ self.transfer_path(with_cwd=with_cwd)
# annotate restart in shell window and mark it
console.text.delete("iomark", "end-1c")
if was_executing:
@@ -492,12 +492,18 @@
except OSError:
return

- def transfer_path(self):
+ def transfer_path(self, with_cwd=False):
+ if with_cwd: # Issue 13506
+ path = [''] # include Current Working Directory
+ path.extend(sys.path)
+ else:
+ path = sys.path
+
self.runcommand("""if 1:
import sys as _sys
_sys.path = %r
del _sys
- \n""" % (sys.path,))
+ \n""" % (path,))

active_seq = None

@@ -1191,7 +1197,8 @@
self.text.see("restart")

def restart_shell(self, event=None):
- self.interp.restart_subprocess()
+ "Callback for Run/Restart Shell Cntl-F6"
+ self.interp.restart_subprocess(with_cwd=True)

def showprompt(self):
self.resetoutput()
diff --git a/Lib/idlelib/ScriptBinding.py b/Lib/idlelib/ScriptBinding.py
--- a/Lib/idlelib/ScriptBinding.py
+++ b/Lib/idlelib/ScriptBinding.py
@@ -144,10 +144,9 @@
return 'break'
if not self.tabnanny(filename):
return 'break'
- shell = self.shell
- interp = shell.interp
+ interp = self.shell.interp
if PyShell.use_subprocess:
- shell.restart_shell()
+ interp.restart_subprocess(with_cwd=False)
dirname = os.path.dirname(filename)
# XXX Too often this discards arguments the user just set...
interp.runcommand("""if 1:
diff --git a/Misc/ACKS b/Misc/ACKS
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -880,6 +880,7 @@
Ty Sarna
Ben Sayer
sbt
+Marco Scataglini
Andrew Schaaf
Michael Scharf
Andreas Schawo
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -463,6 +463,9 @@
Library
-------

+- Issue #13506: Add '' to path for IDLE Shell when started and restarted with Restart Shell.
+ Original patches by Marco Scataglini and Roger Serwy.
+
- Issue #8828: Add new function os.replace(), for cross-platform renaming
with overwriting.

diff --git a/Modules/zipimport.c b/Modules/zipimport.c
--- a/Modules/zipimport.c
+++ b/Modules/zipimport.c
@@ -728,14 +728,15 @@
PyObject *files = NULL;
FILE *fp;
unsigned short flags;
- long compress, crc, data_size, file_size, file_offset, date, time;
- long header_offset, name_size, header_size, header_position;
+ short compress, time, date, name_size;
+ long crc, data_size, file_size, header_size;
+ Py_ssize_t file_offset, header_position, header_offset;
long l, count;
Py_ssize_t i;
char name[MAXPATHLEN + 5];
PyObject *nameobj = NULL;
char *p, endof_central_dir[22];
- long arc_offset; /* offset from beginning of file to start of zip-archive */
+ Py_ssize_t arc_offset; /* Absolute offset to start of the zip-archive. */
PyObject *path;
const char *charset;
int bootstrap;
@@ -835,7 +836,7 @@
path = PyUnicode_FromFormat("%U%c%U", archive, SEP, nameobj);
if (path == NULL)
goto error;
- t = Py_BuildValue("Niiiiiii", path, compress, data_size,
+ t = Py_BuildValue("Nhllnhhl", path, compress, data_size,
file_size, file_offset, time, date, crc);
if (t == NULL)
goto error;

--
Repository URL: http://hg.python.org/cpython
cpython (merge default -> default): Merge [ In reply to ]
http://hg.python.org/cpython/rev/bf24b2e1be24
changeset: 74743:bf24b2e1be24
parent: 74742:404c0c345321
parent: 74741:aa3680d2c24d
user: Brett Cannon <brett@python.org>
date: Fri Feb 03 12:08:32 2012 -0500
summary:
Merge

files:
Doc/library/socket.rst | 8 ++
Misc/ACKS | 1 +
Misc/NEWS | 3 +
Modules/socketmodule.c | 107 +++++++++++++++++++++++++++++
Modules/socketmodule.h | 10 ++
configure | 6 +-
configure.in | 6 +-
pyconfig.h.in | 6 +
8 files changed, 141 insertions(+), 6 deletions(-)


diff --git a/Doc/library/socket.rst b/Doc/library/socket.rst
--- a/Doc/library/socket.rst
+++ b/Doc/library/socket.rst
@@ -99,6 +99,14 @@
``'can0'``. The network interface name ``''`` can be used to receive packets
from all network interfaces of this family.

+- A string or a tuple ``(id, unit)`` is used for the :const:`SYSPROTO_CONTROL`
+ protocol of the :const:`PF_SYSTEM` family. The string is the name of a
+ kernel control using a dynamically-assigned ID. The tuple can be used if ID
+ and unit number of the kernel control are known or if a registered ID is
+ used.
+
+ .. versionadded:: 3.3
+
- Certain other address families (:const:`AF_BLUETOOTH`, :const:`AF_PACKET`)
support specific representations.

diff --git a/Misc/ACKS b/Misc/ACKS
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -366,6 +366,7 @@
Johannes Gijsbers
Michael Gilfix
Yannick Gingras
+Michael Goderbauer
Christoph Gohlke
Tim Golden
Tiago Gonçalves
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -10,6 +10,9 @@
Core and Builtins
-----------------

+- Issue #13777: Add PF_SYSTEM sockets on OS X.
+ Patch by Michael Goderbauer.
+
- Issue #13908: Ready types returned from PyType_FromSpec.

- Issue #11235: Fix OverflowError when trying to import a source file whose
diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c
--- a/Modules/socketmodule.c
+++ b/Modules/socketmodule.c
@@ -218,6 +218,11 @@
# include <ioctl.h>
#endif

+#ifdef __APPLE__
+# include <sys/ioctl.h>
+#endif
+
+
#if defined(PYOS_OS2)
# define INCL_DOS
# define INCL_DOSERRORS
@@ -1239,6 +1244,23 @@
}
#endif

+#ifdef PF_SYSTEM
+ case PF_SYSTEM:
+ switch(proto) {
+#ifdef SYSPROTO_CONTROL
+ case SYSPROTO_CONTROL:
+ {
+ struct sockaddr_ctl *a = (struct sockaddr_ctl *)addr;
+ return Py_BuildValue("(II)", a->sc_id, a->sc_unit);
+ }
+#endif
+ default:
+ PyErr_SetString(PyExc_ValueError,
+ "Invalid address type");
+ return 0;
+ }
+#endif
+
/* More cases here... */

default:
@@ -1677,6 +1699,64 @@
return 0;
}
#endif
+
+#ifdef PF_SYSTEM
+ case PF_SYSTEM:
+ switch (s->sock_proto) {
+#ifdef SYSPROTO_CONTROL
+ case SYSPROTO_CONTROL:
+ {
+ struct sockaddr_ctl *addr;
+
+ addr = (struct sockaddr_ctl *)addr_ret;
+ addr->sc_family = AF_SYSTEM;
+ addr->ss_sysaddr = AF_SYS_CONTROL;
+
+ if (PyUnicode_Check(args)) {
+ struct ctl_info info;
+ PyObject *ctl_name;
+
+ if (!PyArg_Parse(args, "O&",
+ PyUnicode_FSConverter, &ctl_name)) {
+ return 0;
+ }
+
+ if (PyBytes_GET_SIZE(ctl_name) > sizeof(info.ctl_name)) {
+ PyErr_SetString(PyExc_ValueError,
+ "provided string is too long");
+ Py_DECREF(ctl_name);
+ return 0;
+ }
+ strncpy(info.ctl_name, PyBytes_AS_STRING(ctl_name),
+ sizeof(info.ctl_name));
+ Py_DECREF(ctl_name);
+
+ if (ioctl(s->sock_fd, CTLIOCGINFO, &info)) {
+ PyErr_SetString(PyExc_OSError,
+ "cannot find kernel control with provided name");
+ return 0;
+ }
+
+ addr->sc_id = info.ctl_id;
+ addr->sc_unit = 0;
+ } else if (!PyArg_ParseTuple(args, "II",
+ &(addr->sc_id), &(addr->sc_unit))) {
+ PyErr_SetString(PyExc_TypeError, "getsockaddrarg: "
+ "expected str or tuple of two ints");
+
+ return 0;
+ }
+
+ *len_ret = sizeof(*addr);
+ return 1;
+ }
+#endif
+ default:
+ PyErr_SetString(PyExc_OSError,
+ "getsockaddrarg: unsupported PF_SYSTEM protocol");
+ return 0;
+ }
+#endif

/* More cases here... */

@@ -1783,6 +1863,21 @@
return 1;
}
#endif
+
+#ifdef PF_SYSTEM
+ case PF_SYSTEM:
+ switch(s->sock_proto) {
+#ifdef SYSPROTO_CONTROL
+ case SYSPROTO_CONTROL:
+ *len_ret = sizeof (struct sockaddr_ctl);
+ return 1;
+#endif
+ default:
+ PyErr_SetString(PyExc_OSError, "getsockaddrlen: "
+ "unknown PF_SYSTEM protocol");
+ return 0;
+ }
+#endif

/* More cases here... */

@@ -5660,6 +5755,14 @@
PyModule_AddIntConstant(m, "PF_RDS", PF_RDS);
#endif

+/* Kernel event messages */
+#ifdef PF_SYSTEM
+ PyModule_AddIntConstant(m, "PF_SYSTEM", PF_SYSTEM);
+#endif
+#ifdef AF_SYSTEM
+ PyModule_AddIntConstant(m, "AF_SYSTEM", AF_SYSTEM);
+#endif
+
#ifdef AF_PACKET
PyModule_AddIntMacro(m, AF_PACKET);
#endif
@@ -6096,6 +6199,10 @@
PyModule_AddIntConstant(m, "IPPROTO_MAX", IPPROTO_MAX);
#endif

+#ifdef SYSPROTO_CONTROL
+ PyModule_AddIntConstant(m, "SYSPROTO_CONTROL", SYSPROTO_CONTROL);
+#endif
+
/* Some port configuration */
#ifdef IPPORT_RESERVED
PyModule_AddIntConstant(m, "IPPORT_RESERVED", IPPORT_RESERVED);
diff --git a/Modules/socketmodule.h b/Modules/socketmodule.h
--- a/Modules/socketmodule.h
+++ b/Modules/socketmodule.h
@@ -80,6 +80,13 @@
#include <linux/can/raw.h>
#endif

+#ifdef HAVE_SYS_SYS_DOMAIN_H
+#include <sys/sys_domain.h>
+#endif
+#ifdef HAVE_SYS_KERN_CONTROL_H
+#include <sys/kern_control.h>
+#endif
+
#ifndef Py__SOCKET_H
#define Py__SOCKET_H
#ifdef __cplusplus
@@ -138,6 +145,9 @@
#ifdef HAVE_LINUX_CAN_H
struct sockaddr_can can;
#endif
+#ifdef HAVE_SYS_KERN_CONTROL_H
+ struct sockaddr_ctl ctl;
+#endif
} sock_addr_t;

/* The object holding a socket. It holds some extra information,
diff --git a/configure b/configure
--- a/configure
+++ b/configure
@@ -6144,10 +6144,10 @@
sched.h shadow.h signal.h stdint.h stropts.h termios.h \
unistd.h utime.h \
poll.h sys/devpoll.h sys/epoll.h sys/poll.h \
-sys/audioio.h sys/xattr.h sys/bsdtty.h sys/event.h sys/file.h sys/loadavg.h \
-sys/lock.h sys/mkdev.h sys/modem.h \
+sys/audioio.h sys/xattr.h sys/bsdtty.h sys/event.h sys/file.h \
+sys/kern_control.h sys/loadavg.h sys/lock.h sys/mkdev.h sys/modem.h \
sys/param.h sys/select.h sys/sendfile.h sys/socket.h sys/statvfs.h \
-sys/stat.h sys/syscall.h sys/termio.h sys/time.h \
+sys/stat.h sys/syscall.h sys/sys_domain.h sys/termio.h sys/time.h \
sys/times.h sys/types.h sys/uio.h sys/un.h sys/utsname.h sys/wait.h pty.h \
libutil.h sys/resource.h netpacket/packet.h sysexits.h bluetooth.h \
bluetooth/bluetooth.h linux/tipc.h spawn.h util.h
diff --git a/configure.in b/configure.in
--- a/configure.in
+++ b/configure.in
@@ -1334,10 +1334,10 @@
sched.h shadow.h signal.h stdint.h stropts.h termios.h \
unistd.h utime.h \
poll.h sys/devpoll.h sys/epoll.h sys/poll.h \
-sys/audioio.h sys/xattr.h sys/bsdtty.h sys/event.h sys/file.h sys/loadavg.h \
-sys/lock.h sys/mkdev.h sys/modem.h \
+sys/audioio.h sys/xattr.h sys/bsdtty.h sys/event.h sys/file.h \
+sys/kern_control.h sys/loadavg.h sys/lock.h sys/mkdev.h sys/modem.h \
sys/param.h sys/select.h sys/sendfile.h sys/socket.h sys/statvfs.h \
-sys/stat.h sys/syscall.h sys/termio.h sys/time.h \
+sys/stat.h sys/syscall.h sys/sys_domain.h sys/termio.h sys/time.h \
sys/times.h sys/types.h sys/uio.h sys/un.h sys/utsname.h sys/wait.h pty.h \
libutil.h sys/resource.h netpacket/packet.h sysexits.h bluetooth.h \
bluetooth/bluetooth.h linux/tipc.h spawn.h util.h)
diff --git a/pyconfig.h.in b/pyconfig.h.in
--- a/pyconfig.h.in
+++ b/pyconfig.h.in
@@ -908,6 +908,9 @@
/* Define to 1 if you have the <sys/file.h> header file. */
#undef HAVE_SYS_FILE_H

+/* Define to 1 if you have the <sys/kern_control.h> header file. */
+#undef HAVE_SYS_KERN_CONTROL_H
+
/* Define to 1 if you have the <sys/loadavg.h> header file. */
#undef HAVE_SYS_LOADAVG_H

@@ -951,6 +954,9 @@
/* Define to 1 if you have the <sys/syscall.h> header file. */
#undef HAVE_SYS_SYSCALL_H

+/* Define to 1 if you have the <sys/sys_domain.h> header file. */
+#undef HAVE_SYS_SYS_DOMAIN_H
+
/* Define to 1 if you have the <sys/termio.h> header file. */
#undef HAVE_SYS_TERMIO_H


--
Repository URL: http://hg.python.org/cpython
cpython (merge default -> default): Merge [ In reply to ]
http://hg.python.org/cpython/rev/62b183035ed6
changeset: 74817:62b183035ed6
parent: 74816:7d4525a96cf2
parent: 74815:140f7de4d2a5
user: Brett Cannon <brett@python.org>
date: Tue Feb 07 09:20:20 2012 -0500
summary:
Merge

files:
Doc/library/os.rst | 2 +-
Doc/whatsnew/3.3.rst | 2 +-
Lib/os.py | 2 +-
Lib/test/test_os.py | 4 ++--
Lib/test/test_posix.py | 8 ++++----
Misc/NEWS | 5 ++++-
Modules/posixmodule.c | 10 +++++-----
7 files changed, 18 insertions(+), 15 deletions(-)


diff --git a/Doc/library/os.rst b/Doc/library/os.rst
--- a/Doc/library/os.rst
+++ b/Doc/library/os.rst
@@ -769,7 +769,7 @@
.. versionadded:: 3.3


-.. function:: fdlistdir(fd)
+.. function:: flistdir(fd)

Like :func:`listdir`, but uses a file descriptor instead and always returns
strings.
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
@@ -571,7 +571,7 @@

* Other new functions:

- * :func:`~os.fdlistdir` (:issue:`10755`)
+ * :func:`~os.flistdir` (:issue:`10755`)
* :func:`~os.getgrouplist` (:issue:`9344`)


diff --git a/Lib/os.py b/Lib/os.py
--- a/Lib/os.py
+++ b/Lib/os.py
@@ -357,7 +357,7 @@
# whether to follow symlinks
flag = 0 if followlinks else AT_SYMLINK_NOFOLLOW

- names = fdlistdir(topfd)
+ names = flistdir(topfd)
dirs, nondirs = [], []
for name in names:
# Here, we don't use AT_SYMLINK_NOFOLLOW to be consistent with
diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py
--- a/Lib/test/test_os.py
+++ b/Lib/test/test_os.py
@@ -611,8 +611,8 @@
for root, dirs, files, rootfd in os.fwalk(*args):
# check that the FD is valid
os.fstat(rootfd)
- # check that fdlistdir() returns consistent information
- self.assertEqual(set(os.fdlistdir(rootfd)), set(dirs) | set(files))
+ # check that flistdir() returns consistent information
+ self.assertEqual(set(os.flistdir(rootfd)), set(dirs) | set(files))

def test_fd_leak(self):
# Since we're opening a lot of FDs, we must be careful to avoid leaks:
diff --git a/Lib/test/test_posix.py b/Lib/test/test_posix.py
--- a/Lib/test/test_posix.py
+++ b/Lib/test/test_posix.py
@@ -451,18 +451,18 @@
if hasattr(posix, 'listdir'):
self.assertTrue(support.TESTFN in posix.listdir())

- @unittest.skipUnless(hasattr(posix, 'fdlistdir'), "test needs posix.fdlistdir()")
- def test_fdlistdir(self):
+ @unittest.skipUnless(hasattr(posix, 'flistdir'), "test needs posix.flistdir()")
+ def test_flistdir(self):
f = posix.open(posix.getcwd(), posix.O_RDONLY)
self.addCleanup(posix.close, f)
self.assertEqual(
sorted(posix.listdir('.')),
- sorted(posix.fdlistdir(f))
+ sorted(posix.flistdir(f))
)
# Check that the fd offset was reset (issue #13739)
self.assertEqual(
sorted(posix.listdir('.')),
- sorted(posix.fdlistdir(f))
+ sorted(posix.flistdir(f))
)

def test_access(self):
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -466,6 +466,9 @@
Library
-------

+- Issue #10811: Fix recursive usage of cursors. Instead of crashing,
+ raise a ProgrammingError now.
+
- Issue #10881: Fix test_site failure with OS X framework builds.

- Issue #964437 Make IDLE help window non-modal.
@@ -1745,7 +1748,7 @@

- Issue #11297: Add collections.ChainMap().

-- Issue #10755: Add the posix.fdlistdir() function. Patch by Ross Lagerwall.
+- Issue #10755: Add the posix.flistdir() function. Patch by Ross Lagerwall.

- Issue #4761: Add the *at() family of functions (openat(), etc.) to the posix
module. Patch by Ross Lagerwall.
diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c
--- a/Modules/posixmodule.c
+++ b/Modules/posixmodule.c
@@ -2867,12 +2867,12 @@
} /* end of posix_listdir */

#ifdef HAVE_FDOPENDIR
-PyDoc_STRVAR(posix_fdlistdir__doc__,
-"fdlistdir(fd) -> list_of_strings\n\n\
+PyDoc_STRVAR(posix_flistdir__doc__,
+"flistdir(fd) -> list_of_strings\n\n\
Like listdir(), but uses a file descriptor instead.");

static PyObject *
-posix_fdlistdir(PyObject *self, PyObject *args)
+posix_flistdir(PyObject *self, PyObject *args)
{
PyObject *d, *v;
DIR *dirp;
@@ -2880,7 +2880,7 @@
int fd;

errno = 0;
- if (!PyArg_ParseTuple(args, "i:fdlistdir", &fd))
+ if (!PyArg_ParseTuple(args, "i:flistdir", &fd))
return NULL;
/* closedir() closes the FD, so we duplicate it */
fd = dup(fd);
@@ -10555,7 +10555,7 @@
#endif /* HAVE_LINK */
{"listdir", posix_listdir, METH_VARARGS, posix_listdir__doc__},
#ifdef HAVE_FDOPENDIR
- {"fdlistdir", posix_fdlistdir, METH_VARARGS, posix_fdlistdir__doc__},
+ {"flistdir", posix_flistdir, METH_VARARGS, posix_flistdir__doc__},
#endif
{"lstat", posix_lstat, METH_VARARGS, posix_lstat__doc__},
{"mkdir", posix_mkdir, METH_VARARGS, posix_mkdir__doc__},

--
Repository URL: http://hg.python.org/cpython
cpython (merge default -> default): Merge [ In reply to ]
http://hg.python.org/cpython/rev/e9d01c5c92ed
changeset: 74966:e9d01c5c92ed
parent: 74964:9ab501b3e22d
parent: 74962:170a224ce01e
user: Antoine Pitrou <solipsis@pitrou.net>
date: Wed Feb 15 22:30:29 2012 +0100
summary:
Merge

files:
Lib/test/test_pep3120.py | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)


diff --git a/Lib/test/test_pep3120.py b/Lib/test/test_pep3120.py
--- a/Lib/test/test_pep3120.py
+++ b/Lib/test/test_pep3120.py
@@ -19,8 +19,8 @@
try:
import test.badsyntax_pep3120
except SyntaxError as msg:
- msg = str(msg).lower()
- self.assertTrue('utf-8' in msg or 'utf8' in msg)
+ msg = str(msg)
+ self.assertTrue('Non-UTF-8 code starting with' in msg)
else:
self.fail("expected exception didn't occur")


--
Repository URL: http://hg.python.org/cpython
cpython (merge default -> default): Merge [ In reply to ]
http://hg.python.org/cpython/rev/83e833f70977
changeset: 74993:83e833f70977
parent: 74992:45a2bbf6c752
parent: 74991:cdc9e0238b1d
user: Brett Cannon <brett@python.org>
date: Thu Feb 16 18:03:47 2012 -0500
summary:
Merge

files:
Doc/includes/sqlite3/shortcut_methods.py | 3 +-
Doc/library/sqlite3.rst | 11 ++--
Lib/test/test_sched.py | 28 ++++++-----
Lib/test/test_xml_etree.py | 8 +---
Lib/test/test_xml_etree_c.py | 5 +-
Lib/xml/etree/ElementTree.py | 2 +
Misc/NEWS | 4 +-
7 files changed, 30 insertions(+), 31 deletions(-)


diff --git a/Doc/includes/sqlite3/shortcut_methods.py b/Doc/includes/sqlite3/shortcut_methods.py
--- a/Doc/includes/sqlite3/shortcut_methods.py
+++ b/Doc/includes/sqlite3/shortcut_methods.py
@@ -17,5 +17,4 @@
for row in con.execute("select firstname, lastname from person"):
print(row)

-# Using a dummy WHERE clause to not let SQLite take the shortcut table deletes.
-print("I just deleted", con.execute("delete from person where 1=1").rowcount, "rows")
+print("I just deleted", con.execute("delete from person").rowcount, "rows")
diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst
--- a/Doc/library/sqlite3.rst
+++ b/Doc/library/sqlite3.rst
@@ -555,18 +555,17 @@
attribute, the database engine's own support for the determination of "rows
affected"/"rows selected" is quirky.

- For ``DELETE`` statements, SQLite reports :attr:`rowcount` as 0 if you make a
- ``DELETE FROM table`` without any condition.
-
For :meth:`executemany` statements, the number of modifications are summed up
into :attr:`rowcount`.

As required by the Python DB API Spec, the :attr:`rowcount` attribute "is -1 in
case no ``executeXX()`` has been performed on the cursor or the rowcount of the
- last operation is not determinable by the interface".
+ last operation is not determinable by the interface". This includes ``SELECT``
+ statements because we cannot determine the number of rows a query produced
+ until all rows were fetched.

- This includes ``SELECT`` statements because we cannot determine the number of
- rows a query produced until all rows were fetched.
+ With SQLite versions before 3.6.5, :attr:`rowcount` is set to 0 if
+ you make a ``DELETE FROM table`` without any condition.

.. attribute:: Cursor.lastrowid

diff --git a/Lib/test/test_sched.py b/Lib/test/test_sched.py
--- a/Lib/test/test_sched.py
+++ b/Lib/test/test_sched.py
@@ -12,10 +12,10 @@
l = []
fun = lambda x: l.append(x)
scheduler = sched.scheduler(time.time, time.sleep)
- for x in [0.05, 0.04, 0.03, 0.02, 0.01]:
+ for x in [0.5, 0.4, 0.3, 0.2, 0.1]:
z = scheduler.enter(x, 1, fun, (x,))
scheduler.run()
- self.assertEqual(l, [0.01, 0.02, 0.03, 0.04, 0.05])
+ self.assertEqual(l, [0.1, 0.2, 0.3, 0.4, 0.5])

def test_enterabs(self):
l = []
@@ -31,7 +31,7 @@
fun = lambda x: l.append(x)
scheduler = sched.scheduler(time.time, time.sleep)
for priority in [1, 2, 3, 4, 5]:
- z = scheduler.enter(0.01, priority, fun, (priority,))
+ z = scheduler.enterabs(0.01, priority, fun, (priority,))
scheduler.run()
self.assertEqual(l, [1, 2, 3, 4, 5])

@@ -39,11 +39,12 @@
l = []
fun = lambda x: l.append(x)
scheduler = sched.scheduler(time.time, time.sleep)
- event1 = scheduler.enter(0.01, 1, fun, (0.01,))
- event2 = scheduler.enter(0.02, 1, fun, (0.02,))
- event3 = scheduler.enter(0.03, 1, fun, (0.03,))
- event4 = scheduler.enter(0.04, 1, fun, (0.04,))
- event5 = scheduler.enter(0.05, 1, fun, (0.05,))
+ now = time.time()
+ event1 = scheduler.enterabs(now + 0.01, 1, fun, (0.01,))
+ event2 = scheduler.enterabs(now + 0.02, 1, fun, (0.02,))
+ event3 = scheduler.enterabs(now + 0.03, 1, fun, (0.03,))
+ event4 = scheduler.enterabs(now + 0.04, 1, fun, (0.04,))
+ event5 = scheduler.enterabs(now + 0.05, 1, fun, (0.05,))
scheduler.cancel(event1)
scheduler.cancel(event5)
scheduler.run()
@@ -64,11 +65,12 @@
l = []
fun = lambda x: l.append(x)
scheduler = sched.scheduler(time.time, time.sleep)
- e5 = scheduler.enter(0.05, 1, fun)
- e1 = scheduler.enter(0.01, 1, fun)
- e2 = scheduler.enter(0.02, 1, fun)
- e4 = scheduler.enter(0.04, 1, fun)
- e3 = scheduler.enter(0.03, 1, fun)
+ now = time.time()
+ e5 = scheduler.enterabs(now + 0.05, 1, fun)
+ e1 = scheduler.enterabs(now + 0.01, 1, fun)
+ e2 = scheduler.enterabs(now + 0.02, 1, fun)
+ e4 = scheduler.enterabs(now + 0.04, 1, fun)
+ e3 = scheduler.enterabs(now + 0.03, 1, fun)
# queue property is supposed to return an order list of
# upcoming events
self.assertEqual(list(scheduler.queue), [e1, e2, e3, e4, e5])
diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py
--- a/Lib/test/test_xml_etree.py
+++ b/Lib/test/test_xml_etree.py
@@ -1352,7 +1352,6 @@
r"""
Basic inclusion example (XInclude C.1)

- >>> from xml.etree import ElementTree as ET
>>> from xml.etree import ElementInclude

>>> document = xinclude_loader("C1.xml")
@@ -1882,12 +1881,7 @@

def __enter__(self):
from xml.etree import ElementPath
- if hasattr(ET, '_namespace_map'):
- self._nsmap = ET._namespace_map
- else:
- # when testing the cElementTree alias
- from xml.etree.ElementTree import _namespace_map
- self._nsmap = _namespace_map
+ self._nsmap = ET.register_namespace._namespace_map
# Copy the default namespace mapping
self._nsmap_copy = self._nsmap.copy()
# Copy the path cache (should be empty)
diff --git a/Lib/test/test_xml_etree_c.py b/Lib/test/test_xml_etree_c.py
--- a/Lib/test/test_xml_etree_c.py
+++ b/Lib/test/test_xml_etree_c.py
@@ -5,7 +5,7 @@
import unittest

cET = import_fresh_module('xml.etree.ElementTree', fresh=['_elementtree'])
-cET_alias = import_fresh_module('xml.etree.cElementTree', fresh=['_elementtree'])
+cET_alias = import_fresh_module('xml.etree.cElementTree', fresh=['_elementtree', 'xml.etree'])


# cElementTree specific tests
@@ -52,6 +52,9 @@
def test_correct_import_cET(self):
self.assertEqual(cET.Element.__module__, '_elementtree')

+ def test_correct_import_cET_alias(self):
+ self.assertEqual(cET_alias.Element.__module__, '_elementtree')
+

def test_main():
from test import test_xml_etree, test_xml_etree_c
diff --git a/Lib/xml/etree/ElementTree.py b/Lib/xml/etree/ElementTree.py
--- a/Lib/xml/etree/ElementTree.py
+++ b/Lib/xml/etree/ElementTree.py
@@ -1086,6 +1086,8 @@
# dublin core
"http://purl.org/dc/elements/1.1/": "dc",
}
+# For tests and troubleshooting
+register_namespace._namespace_map = _namespace_map

def _raise_serialization_error(text):
raise TypeError(
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -2261,8 +2261,8 @@
Documentation
-------------

-- Issue #13491: Fix many errors in sqlite3 documentation. Initial
- patch by Johannes Vogel.
+- Issues #13491 and #13995: Fix many errors in sqlite3 documentation.
+ Initial patch for #13491 by Johannes Vogel.

- Issue #13402: Document absoluteness of sys.executable.


--
Repository URL: http://hg.python.org/cpython
cpython (merge default -> default): Merge [ In reply to ]
http://hg.python.org/cpython/rev/dee36bfa3f8f
changeset: 75049:dee36bfa3f8f
parent: 75048:bbaab666e6c7
parent: 75047:efd299a3eb7d
user: Antoine Pitrou <solipsis@pitrou.net>
date: Mon Feb 20 01:52:17 2012 +0100
summary:
Merge

files:
Doc/library/argparse.rst | 31 ++++++++++++++-------------
1 files changed, 16 insertions(+), 15 deletions(-)


diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst
--- a/Doc/library/argparse.rst
+++ b/Doc/library/argparse.rst
@@ -739,7 +739,7 @@

* ``'version'`` - This expects a ``version=`` keyword argument in the
:meth:`~ArgumentParser.add_argument` call, and prints version information
- and exits when invoked.
+ and exits when invoked::

>>> import argparse
>>> parser = argparse.ArgumentParser(prog='PROG')
@@ -791,8 +791,8 @@
different number of command-line arguments with a single action. The supported
values are:

-* ``N`` (an integer). ``N`` arguments from the command line will be gathered together into a
- list. For example::
+* ``N`` (an integer). ``N`` arguments from the command line will be gathered
+ together into a list. For example::

>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('--foo', nargs=2)
@@ -861,7 +861,7 @@

* ``argparse.REMAINDER``. All the remaining command-line arguments are gathered
into a list. This is commonly useful for command line utilities that dispatch
- to other command line utilities.
+ to other command line utilities::

>>> parser = argparse.ArgumentParser(prog='PROG')
>>> parser.add_argument('--foo')
@@ -884,7 +884,8 @@

* When :meth:`~ArgumentParser.add_argument` is called with
``action='store_const'`` or ``action='append_const'``. These actions add the
- ``const`` value to one of the attributes of the object returned by :meth:`~ArgumentParser.parse_args`. See the action_ description for examples.
+ ``const`` value to one of the attributes of the object returned by
+ :meth:`~ArgumentParser.parse_args`. See the action_ description for examples.

* When :meth:`~ArgumentParser.add_argument` is called with option strings
(like ``-f`` or ``--foo``) and ``nargs='?'``. This creates an optional
@@ -1595,21 +1596,21 @@
The :class:`FileType` factory creates objects that can be passed to the type
argument of :meth:`ArgumentParser.add_argument`. Arguments that have
:class:`FileType` objects as their type will open command-line arguments as files
- with the requested modes and buffer sizes:
+ with the requested modes and buffer sizes::

- >>> parser = argparse.ArgumentParser()
- >>> parser.add_argument('--output', type=argparse.FileType('wb', 0))
- >>> parser.parse_args(['--output', 'out'])
- Namespace(output=<_io.BufferedWriter name='out'>)
+ >>> parser = argparse.ArgumentParser()
+ >>> parser.add_argument('--output', type=argparse.FileType('wb', 0))
+ >>> parser.parse_args(['--output', 'out'])
+ Namespace(output=<_io.BufferedWriter name='out'>)

FileType objects understand the pseudo-argument ``'-'`` and automatically
convert this into ``sys.stdin`` for readable :class:`FileType` objects and
- ``sys.stdout`` for writable :class:`FileType` objects:
+ ``sys.stdout`` for writable :class:`FileType` objects::

- >>> parser = argparse.ArgumentParser()
- >>> parser.add_argument('infile', type=argparse.FileType('r'))
- >>> parser.parse_args(['-'])
- Namespace(infile=<_io.TextIOWrapper name='<stdin>' encoding='UTF-8'>)
+ >>> parser = argparse.ArgumentParser()
+ >>> parser.add_argument('infile', type=argparse.FileType('r'))
+ >>> parser.parse_args(['-'])
+ Namespace(infile=<_io.TextIOWrapper name='<stdin>' encoding='UTF-8'>)


Argument groups

--
Repository URL: http://hg.python.org/cpython
cpython (merge default -> default): Merge [ In reply to ]
http://hg.python.org/cpython/rev/6f578f73d14a
changeset: 75194:6f578f73d14a
parent: 75193:f95faebf5dea
parent: 75192:8c9638f0587a
user: Brett Cannon <brett@python.org>
date: Thu Feb 23 10:17:56 2012 -0500
summary:
Merge

files:
Lib/test/test_zlib.py | 36 ++++++------------------------
1 files changed, 7 insertions(+), 29 deletions(-)


diff --git a/Lib/test/test_zlib.py b/Lib/test/test_zlib.py
--- a/Lib/test/test_zlib.py
+++ b/Lib/test/test_zlib.py
@@ -7,11 +7,6 @@

zlib = support.import_module('zlib')

-try:
- import mmap
-except ImportError:
- mmap = None
-

class VersionTestCase(unittest.TestCase):

@@ -77,24 +72,11 @@
# Issue #10276 - check that inputs >=4GB are handled correctly.
class ChecksumBigBufferTestCase(unittest.TestCase):

- def setUp(self):
- with open(support.TESTFN, "wb+") as f:
- f.seek(_4G)
- f.write(b"asdf")
- f.flush()
- self.mapping = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ)
-
- def tearDown(self):
- self.mapping.close()
- support.unlink(support.TESTFN)
-
- @unittest.skipUnless(mmap, "mmap() is not available.")
- @unittest.skipUnless(sys.maxsize > _4G, "Can't run on a 32-bit system.")
- @unittest.skipUnless(support.is_resource_enabled("largefile"),
- "May use lots of disk space.")
- def test_big_buffer(self):
- self.assertEqual(zlib.crc32(self.mapping), 3058686908)
- self.assertEqual(zlib.adler32(self.mapping), 82837919)
+ @bigmemtest(size=_4G + 4, memuse=1, dry_run=False)
+ def test_big_buffer(self, size):
+ data = b"nyan" * (_1G + 1)
+ self.assertEqual(zlib.crc32(data), 1044521549)
+ self.assertEqual(zlib.adler32(data), 2256789997)


class ExceptionTestCase(unittest.TestCase):
@@ -197,10 +179,8 @@
def test_big_decompress_buffer(self, size):
self.check_big_decompress_buffer(size, zlib.decompress)

- @bigmemtest(size=_4G + 100, memuse=1)
+ @bigmemtest(size=_4G + 100, memuse=1, dry_run=False)
def test_length_overflow(self, size):
- if size < _4G + 100:
- self.skipTest("not enough free memory, need at least 4 GB")
data = b'x' * size
try:
self.assertRaises(OverflowError, zlib.compress, data, 1)
@@ -554,10 +534,8 @@
decompress = lambda s: d.decompress(s) + d.flush()
self.check_big_decompress_buffer(size, decompress)

- @bigmemtest(size=_4G + 100, memuse=1)
+ @bigmemtest(size=_4G + 100, memuse=1, dry_run=False)
def test_length_overflow(self, size):
- if size < _4G + 100:
- self.skipTest("not enough free memory, need at least 4 GB")
data = b'x' * size
c = zlib.compressobj(1)
d = zlib.decompressobj()

--
Repository URL: http://hg.python.org/cpython
cpython (merge default -> default): merge [ In reply to ]
http://hg.python.org/cpython/rev/548a023c8230
changeset: 75230:548a023c8230
parent: 75229:8d1040fdac60
parent: 75227:50b1f2d07011
user: Brett Cannon <brett@python.org>
date: Thu Feb 23 18:30:04 2012 -0500
summary:
merge

files:
.hgtags | 1 +
Doc/library/subprocess.rst | 2 +-
Doc/library/sys.rst | 5 +-
Doc/library/time.rst | 5 +-
Lib/logging/__init__.py | 28 ++++++++----
Lib/logging/handlers.py | 53 +++++++++++++++++--------
6 files changed, 62 insertions(+), 32 deletions(-)


diff --git a/.hgtags b/.hgtags
--- a/.hgtags
+++ b/.hgtags
@@ -77,6 +77,7 @@
a4f75773c0060cee38b0bb651a7aba6f56b0e996 v3.1.3
32fcb9e94985cb19ce37ba9543f091c0dbe9d7dd v3.1.4rc1
c918ec9f3a76d6afedfbb5d455004de880443a3d v3.1.4
+ee26aca3219cf4bb0b93352e83edcc9cb28c7802 v3.1.5rc1
b37b7834757492d009b99cf0ca4d42d2153d7fac v3.2a1
56d4373cecb73c8b45126ba7b045b3c7b3f94b0b v3.2a2
da012d9a2c23d144e399d2e01a55b8a83ad94573 v3.2a3
diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst
--- a/Doc/library/subprocess.rst
+++ b/Doc/library/subprocess.rst
@@ -240,7 +240,7 @@
When *stdout* or *stderr* are pipes and *universal_newlines* is
:const:`True` then the output data is assumed to be encoded as UTF-8 and
will automatically be decoded to text. All line endings will be converted
- to ``'\n'`` as described for the universal newlines `'U'`` mode argument
+ to ``'\n'`` as described for the universal newlines ``'U'`` mode argument
to :func:`open`.

If *shell* is :const:`True`, the specified command will be executed through
diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst
--- a/Doc/library/sys.rst
+++ b/Doc/library/sys.rst
@@ -195,7 +195,7 @@
be set at build time with the ``--exec-prefix`` argument to the
:program:`configure` script. Specifically, all configuration files (e.g. the
:file:`pyconfig.h` header file) are installed in the directory
- :file:`{exec_prefix}/lib/python{X.Y}/config', and shared library modules are
+ :file:`{exec_prefix}/lib/python{X.Y}/config`, and shared library modules are
installed in :file:`{exec_prefix}/lib/python{X.Y}/lib-dynload`, where *X.Y*
is the version number of Python, for example ``3.2``.

@@ -756,6 +756,7 @@
always use the ``startswith`` idiom presented above.

.. seealso::
+
:attr:`os.name` has a coarser granularity. :func:`os.uname` gives
system-dependent version information.

@@ -771,7 +772,7 @@
argument to the :program:`configure` script. The main collection of Python
library modules is installed in the directory :file:`{prefix}/lib/python{X.Y}``
while the platform independent header files (all except :file:`pyconfig.h`) are
- stored in :file:`{prefix}/include/python{X.Y}``, where *X.Y* is the version
+ stored in :file:`{prefix}/include/python{X.Y}`, where *X.Y* is the version
number of Python, for example ``3.2``.


diff --git a/Doc/library/time.rst b/Doc/library/time.rst
--- a/Doc/library/time.rst
+++ b/Doc/library/time.rst
@@ -228,8 +228,9 @@

.. function:: monotonic()

- Monotonic clock. The reference point of the returned value is undefined so
- only the difference of consecutive calls is valid.
+ Monotonic non-decreasing clock. The clock is not related to the system clock
+ and cannot go backward. The reference point of the returned
+ value is undefined so only the difference of consecutive calls is valid.

.. versionadded:: 3.3

diff --git a/Lib/logging/__init__.py b/Lib/logging/__init__.py
--- a/Lib/logging/__init__.py
+++ b/Lib/logging/__init__.py
@@ -16,9 +16,9 @@

"""
Logging package for Python. Based on PEP 282 and comments thereto in
-comp.lang.python, and influenced by Apache's log4j system.
+comp.lang.python.

-Copyright (C) 2001-2011 Vinay Sajip. All Rights Reserved.
+Copyright (C) 2001-2012 Vinay Sajip. All Rights Reserved.

To use, simply 'import logging' and log away!
"""
@@ -914,8 +914,12 @@
"""
Flushes the stream.
"""
- if self.stream and hasattr(self.stream, "flush"):
- self.stream.flush()
+ self.acquire()
+ try:
+ if self.stream and hasattr(self.stream, "flush"):
+ self.stream.flush()
+ finally:
+ self.release()

def emit(self, record):
"""
@@ -964,12 +968,16 @@
"""
Closes the stream.
"""
- if self.stream:
- self.flush()
- if hasattr(self.stream, "close"):
- self.stream.close()
- StreamHandler.close(self)
- self.stream = None
+ self.acquire()
+ try:
+ if self.stream:
+ self.flush()
+ if hasattr(self.stream, "close"):
+ self.stream.close()
+ StreamHandler.close(self)
+ self.stream = None
+ finally:
+ self.release()

def _open(self):
"""
diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py
--- a/Lib/logging/handlers.py
+++ b/Lib/logging/handlers.py
@@ -1,4 +1,4 @@
-# Copyright 2001-2010 by Vinay Sajip. All Rights Reserved.
+# Copyright 2001-2012 by Vinay Sajip. All Rights Reserved.
#
# Permission to use, copy, modify, and distribute this software and its
# documentation for any purpose and without fee is hereby granted,
@@ -16,10 +16,9 @@

"""
Additional handlers for the logging package for Python. The core package is
-based on PEP 282 and comments thereto in comp.lang.python, and influenced by
-Apache's log4j system.
+based on PEP 282 and comments thereto in comp.lang.python.

-Copyright (C) 2001-2010 Vinay Sajip. All Rights Reserved.
+Copyright (C) 2001-2012 Vinay Sajip. All Rights Reserved.

To use, simply 'import logging.handlers' and log away!
"""
@@ -594,10 +593,14 @@
"""
Closes the socket.
"""
- if self.sock:
- self.sock.close()
- self.sock = None
- logging.Handler.close(self)
+ self.acquire()
+ try:
+ if self.sock:
+ self.sock.close()
+ self.sock = None
+ logging.Handler.close(self)
+ finally:
+ self.release()

class DatagramHandler(SocketHandler):
"""
@@ -792,8 +795,12 @@
"""
Closes the socket.
"""
- self.socket.close()
- logging.Handler.close(self)
+ self.acquire()
+ try:
+ self.socket.close()
+ logging.Handler.close(self)
+ finally:
+ self.release()

def mapPriority(self, levelName):
"""
@@ -1137,7 +1144,11 @@

This version just zaps the buffer to empty.
"""
- self.buffer = []
+ self.acquire()
+ try:
+ self.buffer = []
+ finally:
+ self.release()

def close(self):
"""
@@ -1187,18 +1198,26 @@

The record buffer is also cleared by this operation.
"""
- if self.target:
- for record in self.buffer:
- self.target.handle(record)
- self.buffer = []
+ self.acquire()
+ try:
+ if self.target:
+ for record in self.buffer:
+ self.target.handle(record)
+ self.buffer = []
+ finally:
+ self.release()

def close(self):
"""
Flush, set the target to None and lose the buffer.
"""
self.flush()
- self.target = None
- BufferingHandler.close(self)
+ self.acquire()
+ try:
+ self.target = None
+ BufferingHandler.close(self)
+ finally:
+ self.release()


class QueueHandler(logging.Handler):

--
Repository URL: http://hg.python.org/cpython
cpython (merge default -> default): merge [ In reply to ]
http://hg.python.org/cpython/rev/e394e62473ee
changeset: 75233:e394e62473ee
parent: 75232:2e7a042a4760
parent: 75231:f89e2f4cda88
user: Brett Cannon <brett@python.org>
date: Thu Feb 23 19:34:55 2012 -0500
summary:
merge

files:
Include/unicodeobject.h | 18 +--
Lib/test/test_format.py | 15 ++
Objects/stringlib/asciilib.h | 3 -
Objects/stringlib/localeutil.h | 71 +++------
Objects/stringlib/stringdefs.h | 2 -
Objects/stringlib/ucs1lib.h | 3 -
Objects/stringlib/ucs2lib.h | 3 -
Objects/stringlib/ucs4lib.h | 3 -
Objects/stringlib/undef.h | 2 +-
Objects/stringlib/unicodedefs.h | 2 -
Objects/unicodeobject.c | 77 ++++++++--
Python/formatter_unicode.c | 142 ++++++++++++-------
12 files changed, 189 insertions(+), 152 deletions(-)


diff --git a/Include/unicodeobject.h b/Include/unicodeobject.h
--- a/Include/unicodeobject.h
+++ b/Include/unicodeobject.h
@@ -1936,32 +1936,20 @@
);
#endif

-/* Using the current locale, insert the thousands grouping
- into the string pointed to by buffer. For the argument descriptions,
- see Objects/stringlib/localeutil.h */
-
-#ifndef Py_LIMITED_API
-PyAPI_FUNC(Py_ssize_t) _PyUnicode_InsertThousandsGroupingLocale(Py_UNICODE *buffer,
- Py_ssize_t n_buffer,
- Py_UNICODE *digits,
- Py_ssize_t n_digits,
- Py_ssize_t min_width);
-#endif
-
/* Using explicit passed-in values, insert the thousands grouping
into the string pointed to by buffer. For the argument descriptions,
see Objects/stringlib/localeutil.h */
#ifndef Py_LIMITED_API
PyAPI_FUNC(Py_ssize_t) _PyUnicode_InsertThousandsGrouping(
PyObject *unicode,
- int kind,
- void *buffer,
+ Py_ssize_t index,
Py_ssize_t n_buffer,
void *digits,
Py_ssize_t n_digits,
Py_ssize_t min_width,
const char *grouping,
- const char *thousands_sep);
+ PyObject *thousands_sep,
+ Py_UCS4 *maxchar);
#endif
/* === Characters Type APIs =============================================== */

diff --git a/Lib/test/test_format.py b/Lib/test/test_format.py
--- a/Lib/test/test_format.py
+++ b/Lib/test/test_format.py
@@ -1,4 +1,5 @@
from test.support import verbose, TestFailed
+import locale
import sys
import test.support as support
import unittest
@@ -282,6 +283,20 @@
self.assertEqual(format(1+2j, "\u2007^8"), "\u2007(1+2j)\u2007")
self.assertEqual(format(0j, "\u2007^4"), "\u20070j\u2007")

+ def test_locale(self):
+ try:
+ oldloc = locale.setlocale(locale.LC_ALL, '')
+ except locale.Error as err:
+ self.skipTest("Cannot set locale: {}".format(err))
+ try:
+ sep = locale.localeconv()['thousands_sep']
+ text = format(123456789, "n")
+ self.assertIn(sep, text)
+ self.assertEqual(text.replace(sep, ''), '123456789')
+ finally:
+ locale.setlocale(locale.LC_ALL, oldloc)
+
+

def test_main():
support.run_unittest(FormatTest)
diff --git a/Objects/stringlib/asciilib.h b/Objects/stringlib/asciilib.h
--- a/Objects/stringlib/asciilib.h
+++ b/Objects/stringlib/asciilib.h
@@ -21,12 +21,9 @@
#define STRINGLIB_RESIZE not_supported
#define STRINGLIB_CHECK PyUnicode_Check
#define STRINGLIB_CHECK_EXACT PyUnicode_CheckExact
-#define STRINGLIB_GROUPING _PyUnicode_InsertThousandsGrouping
-#define STRINGLIB_GROUPING_LOCALE _PyUnicode_InsertThousandsGroupingLocale

#define STRINGLIB_TOSTR PyObject_Str
#define STRINGLIB_TOASCII PyObject_ASCII

#define _Py_InsertThousandsGrouping _PyUnicode_ascii_InsertThousandsGrouping
-#define _Py_InsertThousandsGroupingLocale _PyUnicode_ascii_InsertThousandsGroupingLocale

diff --git a/Objects/stringlib/localeutil.h b/Objects/stringlib/localeutil.h
--- a/Objects/stringlib/localeutil.h
+++ b/Objects/stringlib/localeutil.h
@@ -2,8 +2,9 @@

#include <locale.h>

-#define MAX(x, y) ((x) < (y) ? (y) : (x))
-#define MIN(x, y) ((x) < (y) ? (x) : (y))
+#ifndef STRINGLIB_IS_UNICODE
+# error "localeutil is specific to Unicode"
+#endif

typedef struct {
const char *grouping;
@@ -46,7 +47,7 @@
are optional, depending on when we're called. */
static void
STRINGLIB(fill)(STRINGLIB_CHAR **digits_end, STRINGLIB_CHAR **buffer_end,
- Py_ssize_t n_chars, Py_ssize_t n_zeros, const char* thousands_sep,
+ Py_ssize_t n_chars, Py_ssize_t n_zeros, STRINGLIB_CHAR* thousands_sep,
Py_ssize_t thousands_sep_len)
{
Py_ssize_t i;
@@ -55,15 +56,8 @@
*buffer_end -= thousands_sep_len;

/* Copy the thousands_sep chars into the buffer. */
-#if STRINGLIB_IS_UNICODE
- /* Convert from the char's of the thousands_sep from
- the locale into unicode. */
- for (i = 0; i < thousands_sep_len; ++i)
- (*buffer_end)[i] = thousands_sep[i];
-#else
- /* No conversion, just memcpy the thousands_sep. */
- memcpy(*buffer_end, thousands_sep, thousands_sep_len);
-#endif
+ memcpy(*buffer_end, thousands_sep,
+ thousands_sep_len * STRINGLIB_SIZEOF_CHAR);
}

*buffer_end -= n_chars;
@@ -76,7 +70,7 @@
}

/**
- * _Py_InsertThousandsGrouping:
+ * InsertThousandsGrouping:
* @buffer: A pointer to the start of a string.
* @n_buffer: Number of characters in @buffer.
* @digits: A pointer to the digits we're reading from. If count
@@ -106,13 +100,15 @@
_insert_thousands_sep().
**/
Py_ssize_t
-_Py_InsertThousandsGrouping(STRINGLIB_CHAR *buffer,
- Py_ssize_t n_buffer,
- STRINGLIB_CHAR *digits,
- Py_ssize_t n_digits,
- Py_ssize_t min_width,
- const char *grouping,
- const char *thousands_sep)
+STRINGLIB(InsertThousandsGrouping)(
+ STRINGLIB_CHAR *buffer,
+ Py_ssize_t n_buffer,
+ STRINGLIB_CHAR *digits,
+ Py_ssize_t n_digits,
+ Py_ssize_t min_width,
+ const char *grouping,
+ STRINGLIB_CHAR *thousands_sep,
+ Py_ssize_t thousands_sep_len)
{
Py_ssize_t count = 0;
Py_ssize_t n_zeros;
@@ -124,7 +120,6 @@
STRINGLIB_CHAR *digits_end = NULL;
Py_ssize_t l;
Py_ssize_t n_chars;
- Py_ssize_t thousands_sep_len = strlen(thousands_sep);
Py_ssize_t remaining = n_digits; /* Number of chars remaining to
be looked at */
/* A generator that returns all of the grouping widths, until it
@@ -138,9 +133,9 @@
}

while ((l = STRINGLIB(GroupGenerator_next)(&groupgen)) > 0) {
- l = MIN(l, MAX(MAX(remaining, min_width), 1));
- n_zeros = MAX(0, l - remaining);
- n_chars = MAX(0, MIN(remaining, l));
+ l = Py_MIN(l, Py_MAX(Py_MAX(remaining, min_width), 1));
+ n_zeros = Py_MAX(0, l - remaining);
+ n_chars = Py_MAX(0, Py_MIN(remaining, l));

/* Use n_zero zero's and n_chars chars */

@@ -168,9 +163,9 @@
if (!loop_broken) {
/* We left the loop without using a break statement. */

- l = MAX(MAX(remaining, min_width), 1);
- n_zeros = MAX(0, l - remaining);
- n_chars = MAX(0, MIN(remaining, l));
+ l = Py_MAX(Py_MAX(remaining, min_width), 1);
+ n_zeros = Py_MAX(0, l - remaining);
+ n_chars = Py_MAX(0, Py_MIN(remaining, l));

/* Use n_zero zero's and n_chars chars */
count += (use_separator ? thousands_sep_len : 0) + n_zeros + n_chars;
@@ -183,25 +178,3 @@
return count;
}

-/**
- * _Py_InsertThousandsGroupingLocale:
- * @buffer: A pointer to the start of a string.
- * @n_digits: The number of digits in the string, in which we want
- * to put the grouping chars.
- *
- * Reads thee current locale and calls _Py_InsertThousandsGrouping().
- **/
-Py_ssize_t
-_Py_InsertThousandsGroupingLocale(STRINGLIB_CHAR *buffer,
- Py_ssize_t n_buffer,
- STRINGLIB_CHAR *digits,
- Py_ssize_t n_digits,
- Py_ssize_t min_width)
-{
- struct lconv *locale_data = localeconv();
- const char *grouping = locale_data->grouping;
- const char *thousands_sep = locale_data->thousands_sep;
-
- return _Py_InsertThousandsGrouping(buffer, n_buffer, digits, n_digits,
- min_width, grouping, thousands_sep);
-}
diff --git a/Objects/stringlib/stringdefs.h b/Objects/stringlib/stringdefs.h
--- a/Objects/stringlib/stringdefs.h
+++ b/Objects/stringlib/stringdefs.h
@@ -25,7 +25,5 @@
#define STRINGLIB_CHECK PyBytes_Check
#define STRINGLIB_CHECK_EXACT PyBytes_CheckExact
#define STRINGLIB_TOSTR PyObject_Str
-#define STRINGLIB_GROUPING _PyBytes_InsertThousandsGrouping
-#define STRINGLIB_GROUPING_LOCALE _PyBytes_InsertThousandsGroupingLocale
#define STRINGLIB_TOASCII PyObject_Repr
#endif /* !STRINGLIB_STRINGDEFS_H */
diff --git a/Objects/stringlib/ucs1lib.h b/Objects/stringlib/ucs1lib.h
--- a/Objects/stringlib/ucs1lib.h
+++ b/Objects/stringlib/ucs1lib.h
@@ -21,13 +21,10 @@
#define STRINGLIB_RESIZE not_supported
#define STRINGLIB_CHECK PyUnicode_Check
#define STRINGLIB_CHECK_EXACT PyUnicode_CheckExact
-#define STRINGLIB_GROUPING _PyUnicode_InsertThousandsGrouping
-#define STRINGLIB_GROUPING_LOCALE _PyUnicode_InsertThousandsGroupingLocale

#define STRINGLIB_TOSTR PyObject_Str
#define STRINGLIB_TOASCII PyObject_ASCII

#define _Py_InsertThousandsGrouping _PyUnicode_ucs1_InsertThousandsGrouping
-#define _Py_InsertThousandsGroupingLocale _PyUnicode_ucs1_InsertThousandsGroupingLocale


diff --git a/Objects/stringlib/ucs2lib.h b/Objects/stringlib/ucs2lib.h
--- a/Objects/stringlib/ucs2lib.h
+++ b/Objects/stringlib/ucs2lib.h
@@ -21,12 +21,9 @@
#define STRINGLIB_RESIZE not_supported
#define STRINGLIB_CHECK PyUnicode_Check
#define STRINGLIB_CHECK_EXACT PyUnicode_CheckExact
-#define STRINGLIB_GROUPING _PyUnicode_InsertThousandsGrouping
-#define STRINGLIB_GROUPING_LOCALE _PyUnicode_InsertThousandsGroupingLocale

#define STRINGLIB_TOSTR PyObject_Str
#define STRINGLIB_TOASCII PyObject_ASCII

#define _Py_InsertThousandsGrouping _PyUnicode_ucs2_InsertThousandsGrouping
-#define _Py_InsertThousandsGroupingLocale _PyUnicode_ucs2_InsertThousandsGroupingLocale

diff --git a/Objects/stringlib/ucs4lib.h b/Objects/stringlib/ucs4lib.h
--- a/Objects/stringlib/ucs4lib.h
+++ b/Objects/stringlib/ucs4lib.h
@@ -21,12 +21,9 @@
#define STRINGLIB_RESIZE not_supported
#define STRINGLIB_CHECK PyUnicode_Check
#define STRINGLIB_CHECK_EXACT PyUnicode_CheckExact
-#define STRINGLIB_GROUPING _PyUnicode_InsertThousandsGrouping
-#define STRINGLIB_GROUPING_LOCALE _PyUnicode_InsertThousandsGroupingLocale

#define STRINGLIB_TOSTR PyObject_Str
#define STRINGLIB_TOASCII PyObject_ASCII

#define _Py_InsertThousandsGrouping _PyUnicode_ucs4_InsertThousandsGrouping
-#define _Py_InsertThousandsGroupingLocale _PyUnicode_ucs4_InsertThousandsGroupingLocale

diff --git a/Objects/stringlib/undef.h b/Objects/stringlib/undef.h
--- a/Objects/stringlib/undef.h
+++ b/Objects/stringlib/undef.h
@@ -7,5 +7,5 @@
#undef STRINGLIB_NEW
#undef STRINGLIB_RESIZE
#undef _Py_InsertThousandsGrouping
-#undef _Py_InsertThousandsGroupingLocale
+#undef STRINGLIB_IS_UNICODE

diff --git a/Objects/stringlib/unicodedefs.h b/Objects/stringlib/unicodedefs.h
--- a/Objects/stringlib/unicodedefs.h
+++ b/Objects/stringlib/unicodedefs.h
@@ -24,8 +24,6 @@
#define STRINGLIB_RESIZE PyUnicode_Resize
#define STRINGLIB_CHECK PyUnicode_Check
#define STRINGLIB_CHECK_EXACT PyUnicode_CheckExact
-#define STRINGLIB_GROUPING _PyUnicode_InsertThousandsGrouping
-#define STRINGLIB_GROUPING_LOCALE _PyUnicode_InsertThousandsGroupingLocale

#if PY_VERSION_HEX < 0x03000000
#define STRINGLIB_TOSTR PyObject_Unicode
diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c
--- a/Objects/unicodeobject.c
+++ b/Objects/unicodeobject.c
@@ -9151,34 +9151,75 @@
}

Py_ssize_t
-_PyUnicode_InsertThousandsGrouping(PyObject *unicode, int kind, void *data,
- Py_ssize_t n_buffer,
- void *digits, Py_ssize_t n_digits,
- Py_ssize_t min_width,
- const char *grouping,
- const char *thousands_sep)
-{
+_PyUnicode_InsertThousandsGrouping(
+ PyObject *unicode, Py_ssize_t index,
+ Py_ssize_t n_buffer,
+ void *digits, Py_ssize_t n_digits,
+ Py_ssize_t min_width,
+ const char *grouping, PyObject *thousands_sep,
+ Py_UCS4 *maxchar)
+{
+ unsigned int kind, thousands_sep_kind;
+ void *data, *thousands_sep_data;
+ Py_ssize_t thousands_sep_len;
+ Py_ssize_t len;
+
+ if (unicode != NULL) {
+ kind = PyUnicode_KIND(unicode);
+ data = PyUnicode_DATA(unicode) + index * kind;
+ }
+ else {
+ kind = PyUnicode_1BYTE_KIND;
+ data = NULL;
+ }
+ thousands_sep_kind = PyUnicode_KIND(thousands_sep);
+ thousands_sep_data = PyUnicode_DATA(thousands_sep);
+ thousands_sep_len = PyUnicode_GET_LENGTH(thousands_sep);
+ if (unicode != NULL && thousands_sep_kind != kind) {
+ thousands_sep_data = _PyUnicode_AsKind(thousands_sep, kind);
+ if (!thousands_sep_data)
+ return -1;
+ }
+
switch (kind) {
case PyUnicode_1BYTE_KIND:
if (unicode != NULL && PyUnicode_IS_ASCII(unicode))
- return _PyUnicode_ascii_InsertThousandsGrouping(
+ len = asciilib_InsertThousandsGrouping(
(Py_UCS1*)data, n_buffer, (Py_UCS1*)digits, n_digits,
- min_width, grouping, thousands_sep);
+ min_width, grouping,
+ thousands_sep_data, thousands_sep_len);
else
- return _PyUnicode_ucs1_InsertThousandsGrouping(
+ len = ucs1lib_InsertThousandsGrouping(
(Py_UCS1*)data, n_buffer, (Py_UCS1*)digits, n_digits,
- min_width, grouping, thousands_sep);
+ min_width, grouping,
+ thousands_sep_data, thousands_sep_len);
+ break;
case PyUnicode_2BYTE_KIND:
- return _PyUnicode_ucs2_InsertThousandsGrouping(
+ len = ucs2lib_InsertThousandsGrouping(
(Py_UCS2*)data, n_buffer, (Py_UCS2*)digits, n_digits,
- min_width, grouping, thousands_sep);
+ min_width, grouping,
+ thousands_sep_data, thousands_sep_len);
+ break;
case PyUnicode_4BYTE_KIND:
- return _PyUnicode_ucs4_InsertThousandsGrouping(
+ len = ucs4lib_InsertThousandsGrouping(
(Py_UCS4*)data, n_buffer, (Py_UCS4*)digits, n_digits,
- min_width, grouping, thousands_sep);
- }
- assert(0);
- return -1;
+ min_width, grouping,
+ thousands_sep_data, thousands_sep_len);
+ break;
+ default:
+ assert(0);
+ return -1;
+ }
+ if (unicode != NULL && thousands_sep_kind != kind)
+ PyMem_Free(thousands_sep_data);
+ if (unicode == NULL) {
+ *maxchar = 127;
+ if (len != n_digits) {
+ *maxchar = Py_MAX(*maxchar,
+ PyUnicode_MAX_CHAR_VALUE(thousands_sep));
+ }
+ }
+ return len;
}


diff --git a/Python/formatter_unicode.c b/Python/formatter_unicode.c
--- a/Python/formatter_unicode.c
+++ b/Python/formatter_unicode.c
@@ -346,11 +346,13 @@
before and including the decimal. Note that locales only support
8-bit chars, not unicode. */
typedef struct {
- char *decimal_point;
- char *thousands_sep;
- char *grouping;
+ PyObject *decimal_point;
+ PyObject *thousands_sep;
+ const char *grouping;
} LocaleInfo;

+#define STATIC_LOCALE_INFO_INIT {0, 0, 0}
+
/* describes the layout for an integer, see the comment in
calc_number_widths() for details */
typedef struct {
@@ -415,7 +417,7 @@
Py_UCS4 sign_char, PyObject *number, Py_ssize_t n_start,
Py_ssize_t n_end, Py_ssize_t n_remainder,
int has_decimal, const LocaleInfo *locale,
- const InternalFormatSpec *format)
+ const InternalFormatSpec *format, Py_UCS4 *maxchar)
{
Py_ssize_t n_non_digit_non_padding;
Py_ssize_t n_padding;
@@ -423,7 +425,7 @@
spec->n_digits = n_end - n_start - n_remainder - (has_decimal?1:0);
spec->n_lpadding = 0;
spec->n_prefix = n_prefix;
- spec->n_decimal = has_decimal ? strlen(locale->decimal_point) : 0;
+ spec->n_decimal = has_decimal ? PyUnicode_GET_LENGTH(locale->decimal_point) : 0;
spec->n_remainder = n_remainder;
spec->n_spadding = 0;
spec->n_rpadding = 0;
@@ -484,11 +486,15 @@
to special case it because the grouping code always wants
to have at least one character. */
spec->n_grouped_digits = 0;
- else
+ else {
+ Py_UCS4 grouping_maxchar;
spec->n_grouped_digits = _PyUnicode_InsertThousandsGrouping(
- NULL, PyUnicode_1BYTE_KIND, NULL, 0, NULL,
+ NULL, 0,
+ 0, NULL,
spec->n_digits, spec->n_min_width,
- locale->grouping, locale->thousands_sep);
+ locale->grouping, locale->thousands_sep, &grouping_maxchar);
+ *maxchar = Py_MAX(*maxchar, grouping_maxchar);
+ }

/* Given the desired width and the total of digit and non-digit
space we consume, see if we need any padding. format->width can
@@ -519,6 +525,10 @@
break;
}
}
+
+ if (spec->n_lpadding || spec->n_spadding || spec->n_rpadding)
+ *maxchar = Py_MAX(*maxchar, format->fill_char);
+
return spec->n_lpadding + spec->n_sign + spec->n_prefix +
spec->n_spadding + spec->n_grouped_digits + spec->n_decimal +
spec->n_remainder + spec->n_rpadding;
@@ -587,12 +597,11 @@
r =
#endif
_PyUnicode_InsertThousandsGrouping(
- out, kind,
- (char*)data + kind * pos,
+ out, pos,
spec->n_grouped_digits,
pdigits + kind * d_pos,
spec->n_digits, spec->n_min_width,
- locale->grouping, locale->thousands_sep);
+ locale->grouping, locale->thousands_sep, NULL);
#ifndef NDEBUG
assert(r == spec->n_grouped_digits);
#endif
@@ -615,10 +624,8 @@
pos += spec->n_grouped_digits;

if (spec->n_decimal) {
- Py_ssize_t t;
- for (t = 0; t < spec->n_decimal; ++t)
- PyUnicode_WRITE(kind, data, pos + t,
- locale->decimal_point[t]);
+ if (PyUnicode_CopyCharacters(out, pos, locale->decimal_point, 0, spec->n_decimal) < 0)
+ return -1;
pos += spec->n_decimal;
d_pos += 1;
}
@@ -643,32 +650,60 @@
grouping description, either for the current locale if type is
LT_CURRENT_LOCALE, a hard-coded locale if LT_DEFAULT_LOCALE, or
none if LT_NO_LOCALE. */
-static void
+static int
get_locale_info(int type, LocaleInfo *locale_info)
{
switch (type) {
case LT_CURRENT_LOCALE: {
struct lconv *locale_data = localeconv();
- locale_info->decimal_point = locale_data->decimal_point;
- locale_info->thousands_sep = locale_data->thousands_sep;
+ locale_info->decimal_point = PyUnicode_DecodeLocale(
+ locale_data->decimal_point,
+ NULL);
+ if (locale_info->decimal_point == NULL)
+ return -1;
+ locale_info->thousands_sep = PyUnicode_DecodeLocale(
+ locale_data->thousands_sep,
+ NULL);
+ if (locale_info->thousands_sep == NULL) {
+ Py_DECREF(locale_info->decimal_point);
+ return -1;
+ }
locale_info->grouping = locale_data->grouping;
break;
}
case LT_DEFAULT_LOCALE:
- locale_info->decimal_point = ".";
- locale_info->thousands_sep = ",";
+ locale_info->decimal_point = PyUnicode_FromOrdinal('.');
+ locale_info->thousands_sep = PyUnicode_FromOrdinal(',');
+ if (!locale_info->decimal_point || !locale_info->thousands_sep) {
+ Py_XDECREF(locale_info->decimal_point);
+ Py_XDECREF(locale_info->thousands_sep);
+ return -1;
+ }
locale_info->grouping = "\3"; /* Group every 3 characters. The
(implicit) trailing 0 means repeat
infinitely. */
break;
case LT_NO_LOCALE:
- locale_info->decimal_point = ".";
- locale_info->thousands_sep = "";
+ locale_info->decimal_point = PyUnicode_FromOrdinal('.');
+ locale_info->thousands_sep = PyUnicode_New(0, 0);
+ if (!locale_info->decimal_point || !locale_info->thousands_sep) {
+ Py_XDECREF(locale_info->decimal_point);
+ Py_XDECREF(locale_info->thousands_sep);
+ return -1;
+ }
locale_info->grouping = no_grouping;
break;
default:
assert(0);
}
+ return 0;
+}
+
+static void
+free_locale_info(LocaleInfo *locale_info)
+{
+ Py_XDECREF(locale_info->decimal_point);
+ Py_XDECREF(locale_info->thousands_sep);
}

/************************************************************************/
@@ -769,7 +804,7 @@

/* Locale settings, either from the actual locale or
from a hard-code pseudo-locale */
- LocaleInfo locale;
+ LocaleInfo locale = STATIC_LOCALE_INFO_INIT;

/* no precision allowed on integers */
if (format->precision != -1) {
@@ -868,18 +903,17 @@
}

/* Determine the grouping, separator, and decimal point, if any. */
- get_locale_info(format->type == 'n' ? LT_CURRENT_LOCALE :
- (format->thousands_separators ?
- LT_DEFAULT_LOCALE :
- LT_NO_LOCALE),
- &locale);
+ if (get_locale_info(format->type == 'n' ? LT_CURRENT_LOCALE :
+ (format->thousands_separators ?
+ LT_DEFAULT_LOCALE :
+ LT_NO_LOCALE),
+ &locale) == -1)
+ goto done;

/* Calculate how much memory we'll need. */
n_total = calc_number_widths(&spec, n_prefix, sign_char, tmp, inumeric_chars,
- inumeric_chars + n_digits, n_remainder, 0, &locale, format);
-
- if (spec.n_lpadding || spec.n_spadding || spec.n_rpadding)
- maxchar = Py_MAX(maxchar, format->fill_char);
+ inumeric_chars + n_digits, n_remainder, 0,
+ &locale, format, &maxchar);

/* Allocate the memory. */
result = PyUnicode_New(n_total, maxchar);
@@ -897,6 +931,7 @@

done:
Py_XDECREF(tmp);
+ free_locale_info(&locale);
assert(!result || _PyUnicode_CheckConsistency(result, 1));
return result;
}
@@ -938,7 +973,7 @@

/* Locale settings, either from the actual locale or
from a hard-code pseudo-locale */
- LocaleInfo locale;
+ LocaleInfo locale = STATIC_LOCALE_INFO_INIT;

if (format->alternate)
flags |= Py_DTSF_ALT;
@@ -1009,19 +1044,17 @@
parse_number(unicode_tmp, index, index + n_digits, &n_remainder, &has_decimal);

/* Determine the grouping, separator, and decimal point, if any. */
- get_locale_info(format->type == 'n' ? LT_CURRENT_LOCALE :
- (format->thousands_separators ?
- LT_DEFAULT_LOCALE :
- LT_NO_LOCALE),
- &locale);
+ if (get_locale_info(format->type == 'n' ? LT_CURRENT_LOCALE :
+ (format->thousands_separators ?
+ LT_DEFAULT_LOCALE :
+ LT_NO_LOCALE),
+ &locale) == -1)
+ goto done;

/* Calculate how much memory we'll need. */
n_total = calc_number_widths(&spec, 0, sign_char, unicode_tmp, index,
index + n_digits, n_remainder, has_decimal,
- &locale, format);
-
- if (spec.n_lpadding || spec.n_spadding || spec.n_rpadding)
- maxchar = Py_MAX(maxchar, format->fill_char);
+ &locale, format, &maxchar);

/* Allocate the memory. */
result = PyUnicode_New(n_total, maxchar);
@@ -1040,6 +1073,7 @@
done:
PyMem_Free(buf);
Py_DECREF(unicode_tmp);
+ free_locale_info(&locale);
assert(!result || _PyUnicode_CheckConsistency(result, 1));
return result;
}
@@ -1094,7 +1128,7 @@

/* Locale settings, either from the actual locale or
from a hard-code pseudo-locale */
- LocaleInfo locale;
+ LocaleInfo locale = STATIC_LOCALE_INFO_INIT;

/* Zero padding is not allowed. */
if (format->fill_char == '0') {
@@ -1190,11 +1224,12 @@
&n_im_remainder, &im_has_decimal);

/* Determine the grouping, separator, and decimal point, if any. */
- get_locale_info(format->type == 'n' ? LT_CURRENT_LOCALE :
- (format->thousands_separators ?
- LT_DEFAULT_LOCALE :
- LT_NO_LOCALE),
- &locale);
+ if (get_locale_info(format->type == 'n' ? LT_CURRENT_LOCALE :
+ (format->thousands_separators ?
+ LT_DEFAULT_LOCALE :
+ LT_NO_LOCALE),
+ &locale) == -1)
+ goto done;

/* Turn off any padding. We'll do it later after we've composed
the numbers without padding. */
@@ -1205,7 +1240,8 @@
/* Calculate how much memory we'll need. */
n_re_total = calc_number_widths(&re_spec, 0, re_sign_char, re_unicode_tmp,
i_re, i_re + n_re_digits, n_re_remainder,
- re_has_decimal, &locale, &tmp_format);
+ re_has_decimal, &locale, &tmp_format,
+ &maxchar);

/* Same formatting, but always include a sign, unless the real part is
* going to be omitted, in which case we use whatever sign convention was
@@ -1214,7 +1250,8 @@
tmp_format.sign = '+';
n_im_total = calc_number_widths(&im_spec, 0, im_sign_char, im_unicode_tmp,
i_im, i_im + n_im_digits, n_im_remainder,
- im_has_decimal, &locale, &tmp_format);
+ im_has_decimal, &locale, &tmp_format,
+ &maxchar);

if (skip_re)
n_re_total = 0;
@@ -1223,9 +1260,7 @@
calc_padding(n_re_total + n_im_total + 1 + add_parens * 2,
format->width, format->align, &lpad, &rpad, &total);

- if (re_spec.n_lpadding || re_spec.n_spadding || re_spec.n_rpadding
- || im_spec.n_lpadding || im_spec.n_spadding || im_spec.n_rpadding
- || lpad || rpad)
+ if (lpad || rpad)
maxchar = Py_MAX(maxchar, format->fill_char);

result = PyUnicode_New(total, maxchar);
@@ -1275,6 +1310,7 @@
PyMem_Free(im_buf);
Py_XDECREF(re_unicode_tmp);
Py_XDECREF(im_unicode_tmp);
+ free_locale_info(&locale);
assert(!result || _PyUnicode_CheckConsistency(result, 1));
return result;
}

--
Repository URL: http://hg.python.org/cpython
cpython (merge default -> default): merge [ In reply to ]
http://hg.python.org/cpython/rev/aceedef02c63
changeset: 75236:aceedef02c63
parent: 75235:3670df23081d
parent: 75234:a29d20fa85b4
user: Brett Cannon <brett@python.org>
date: Thu Feb 23 20:48:13 2012 -0500
summary:
merge

files:
Lib/test/test_format.py | 10 +++++++++-
Objects/unicodeobject.c | 21 ++++++++++++++++-----
Python/formatter_unicode.c | 15 ++++++---------
3 files changed, 31 insertions(+), 15 deletions(-)


diff --git a/Lib/test/test_format.py b/Lib/test/test_format.py
--- a/Lib/test/test_format.py
+++ b/Lib/test/test_format.py
@@ -289,10 +289,18 @@
except locale.Error as err:
self.skipTest("Cannot set locale: {}".format(err))
try:
- sep = locale.localeconv()['thousands_sep']
+ localeconv = locale.localeconv()
+ sep = localeconv['thousands_sep']
+ point = localeconv['decimal_point']
+
text = format(123456789, "n")
self.assertIn(sep, text)
self.assertEqual(text.replace(sep, ''), '123456789')
+
+ text = format(1234.5, "n")
+ self.assertIn(sep, text)
+ self.assertIn(point, text)
+ self.assertEqual(text.replace(sep, ''), '1234' + point + '5')
finally:
locale.setlocale(locale.LC_ALL, oldloc)

diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c
--- a/Objects/unicodeobject.c
+++ b/Objects/unicodeobject.c
@@ -9176,9 +9176,16 @@
thousands_sep_data = PyUnicode_DATA(thousands_sep);
thousands_sep_len = PyUnicode_GET_LENGTH(thousands_sep);
if (unicode != NULL && thousands_sep_kind != kind) {
- thousands_sep_data = _PyUnicode_AsKind(thousands_sep, kind);
- if (!thousands_sep_data)
- return -1;
+ if (thousands_sep_kind < kind) {
+ thousands_sep_data = _PyUnicode_AsKind(thousands_sep, kind);
+ if (!thousands_sep_data)
+ return -1;
+ }
+ else {
+ data = _PyUnicode_AsKind(unicode, thousands_sep_kind);
+ if (!data)
+ return -1;
+ }
}

switch (kind) {
@@ -9210,8 +9217,12 @@
assert(0);
return -1;
}
- if (unicode != NULL && thousands_sep_kind != kind)
- PyMem_Free(thousands_sep_data);
+ if (unicode != NULL && thousands_sep_kind != kind) {
+ if (thousands_sep_kind < kind)
+ PyMem_Free(thousands_sep_data);
+ else
+ PyMem_Free(data);
+ }
if (unicode == NULL) {
*maxchar = 127;
if (len != n_digits) {
diff --git a/Python/formatter_unicode.c b/Python/formatter_unicode.c
--- a/Python/formatter_unicode.c
+++ b/Python/formatter_unicode.c
@@ -529,6 +529,9 @@
if (spec->n_lpadding || spec->n_spadding || spec->n_rpadding)
*maxchar = Py_MAX(*maxchar, format->fill_char);

+ if (spec->n_decimal)
+ *maxchar = Py_MAX(*maxchar, PyUnicode_MAX_CHAR_VALUE(locale->decimal_point));
+
return spec->n_lpadding + spec->n_sign + spec->n_prefix +
spec->n_spadding + spec->n_grouped_digits + spec->n_decimal +
spec->n_remainder + spec->n_rpadding;
@@ -548,10 +551,7 @@
Py_ssize_t d_pos = d_start;
unsigned int kind = PyUnicode_KIND(out);
void *data = PyUnicode_DATA(out);
-
-#ifndef NDEBUG
Py_ssize_t r;
-#endif

if (spec->n_lpadding) {
PyUnicode_Fill(out, pos, pos + spec->n_lpadding, fill_char);
@@ -593,18 +593,15 @@
if (pdigits == NULL)
return -1;
}
-#ifndef NDEBUG
- r =
-#endif
- _PyUnicode_InsertThousandsGrouping(
+ r = _PyUnicode_InsertThousandsGrouping(
out, pos,
spec->n_grouped_digits,
pdigits + kind * d_pos,
spec->n_digits, spec->n_min_width,
locale->grouping, locale->thousands_sep, NULL);
-#ifndef NDEBUG
+ if (r == -1)
+ return -1;
assert(r == spec->n_grouped_digits);
-#endif
if (PyUnicode_KIND(digits) < kind)
PyMem_Free(pdigits);
d_pos += spec->n_digits;

--
Repository URL: http://hg.python.org/cpython
cpython (merge default -> default): Merge [ In reply to ]
http://hg.python.org/cpython/rev/f417aff64dcc
changeset: 75306:f417aff64dcc
parent: 75305:dc0682e0b0cf
parent: 75300:17562834a246
user: Antoine Pitrou <solipsis@pitrou.net>
date: Mon Feb 27 01:01:58 2012 +0100
summary:
Merge

files:



--
Repository URL: http://hg.python.org/cpython
cpython (merge default -> default): Merge [ In reply to ]
http://hg.python.org/cpython/rev/72d1b21ee10f
changeset: 75400:72d1b21ee10f
parent: 75399:2843f32a3a34
parent: 75396:575a2affd214
user: Antoine Pitrou <solipsis@pitrou.net>
date: Sun Mar 04 20:59:01 2012 +0100
summary:
Merge

files:
Lib/test/crashers/loosing_mro_ref.py | 0
PCbuild/pcbuild.sln | 12 +++++-----
Tools/msi/msi.py | 19 +++++++++------
3 files changed, 17 insertions(+), 14 deletions(-)


diff --git a/Lib/test/crashers/loosing_mro_ref.py b/Lib/test/crashers/losing_mro_ref.py
rename from Lib/test/crashers/loosing_mro_ref.py
rename to Lib/test/crashers/losing_mro_ref.py
diff --git a/PCbuild/pcbuild.sln b/PCbuild/pcbuild.sln
--- a/PCbuild/pcbuild.sln
+++ b/PCbuild/pcbuild.sln
@@ -584,16 +584,16 @@
{6DE10744-E396-40A5-B4E2-1B69AA7C8D31}.Release|x64.ActiveCfg = Release|x64
{6DE10744-E396-40A5-B4E2-1B69AA7C8D31}.Release|x64.Build.0 = Release|x64
{885D4898-D08D-4091-9C40-C700CFE3FC5A}.Debug|Win32.ActiveCfg = PGInstrument|Win32
- {885D4898-D08D-4091-9C40-C700CFE3FC5A}.Debug|x64.ActiveCfg = Debug|x64
- {885D4898-D08D-4091-9C40-C700CFE3FC5A}.Debug|x64.Build.0 = Debug|x64
+ {885D4898-D08D-4091-9C40-C700CFE3FC5A}.Debug|x64.ActiveCfg = PGUpdate|x64
+ {885D4898-D08D-4091-9C40-C700CFE3FC5A}.Debug|x64.Build.0 = PGUpdate|x64
{885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32
{885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGInstrument|Win32.Build.0 = PGInstrument|Win32
- {885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGInstrument|x64.ActiveCfg = Release|x64
- {885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGInstrument|x64.Build.0 = Release|x64
+ {885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGInstrument|x64.ActiveCfg = PGInstrument|x64
+ {885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGInstrument|x64.Build.0 = PGInstrument|x64
{885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGUpdate|Win32.ActiveCfg = PGUpdate|Win32
{885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGUpdate|Win32.Build.0 = PGUpdate|Win32
- {885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGUpdate|x64.ActiveCfg = Release|x64
- {885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGUpdate|x64.Build.0 = Release|x64
+ {885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGUpdate|x64.ActiveCfg = PGUpdate|x64
+ {885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGUpdate|x64.Build.0 = PGUpdate|x64
{885D4898-D08D-4091-9C40-C700CFE3FC5A}.Release|Win32.ActiveCfg = Release|Win32
{885D4898-D08D-4091-9C40-C700CFE3FC5A}.Release|Win32.Build.0 = Release|Win32
{885D4898-D08D-4091-9C40-C700CFE3FC5A}.Release|x64.ActiveCfg = Release|x64
diff --git a/Tools/msi/msi.py b/Tools/msi/msi.py
--- a/Tools/msi/msi.py
+++ b/Tools/msi/msi.py
@@ -6,7 +6,6 @@
import uisample
from win32com.client import constants
from distutils.spawn import find_executable
-from uuids import product_codes
import tempfile

# Settings can be overridden in config.py below
@@ -77,9 +76,6 @@

if snapshot:
current_version = "%s.%s.%s" % (major, minor, int(time.time()/3600/24))
- product_code = msilib.gen_uuid()
-else:
- product_code = product_codes[current_version]

if full_current_version is None:
full_current_version = current_version
@@ -187,12 +183,19 @@
msilib.set_arch_from_file(dll_path)
if msilib.pe_type(dll_path) != msilib.pe_type("msisupport.dll"):
raise SystemError("msisupport.dll for incorrect architecture")
+
if msilib.Win64:
upgrade_code = upgrade_code_64
- # Bump the last digit of the code by one, so that 32-bit and 64-bit
- # releases get separate product codes
- digit = hex((int(product_code[-2],16)+1)%16)[-1]
- product_code = product_code[:-2] + digit + '}'
+
+if snapshot:
+ product_code = msilib.gen_uuid()
+else:
+ # official release: generate UUID from the download link that the file will have
+ import uuid
+ product_code = uuid.uuid3(uuid.NAMESPACE_URL,
+ 'http://www.python.org/ftp/python/%s.%s.%s/python-%s%s.msi' %
+ (major, minor, micro, full_current_version, msilib.arch_ext))
+ product_code = '{%s}' % product_code

if testpackage:
ext = 'px'

--
Repository URL: http://hg.python.org/cpython
cpython (merge default -> default): Merge [ In reply to ]
http://hg.python.org/cpython/rev/8639ec6f3d06
changeset: 75454:8639ec6f3d06
parent: 75453:7069d0a55470
parent: 75451:538cbae3ec2d
user: Antoine Pitrou <solipsis@pitrou.net>
date: Tue Mar 06 13:45:57 2012 +0100
summary:
Merge

files:
Doc/whatsnew/3.3.rst | 72 +++++++++++++++++++++++++++++--
1 files changed, 67 insertions(+), 5 deletions(-)


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
@@ -49,6 +49,8 @@
This article explains the new features in Python 3.3, compared to 3.2.


+.. pep-3118-update:
+
PEP 3118: New memoryview implementation and buffer protocol documentation
=========================================================================

@@ -85,7 +87,9 @@
* Multi-dimensional comparisons are supported for any array type.

* All array types are hashable if the exporting object is hashable
- and the view is read-only.
+ and the view is read-only. (Contributed by Antoine Pitrou in
+ :issue:`13411`)
+

* Arbitrary slicing of any 1-D arrays type is supported. For example, it
is now possible to reverse a memoryview in O(1) by using a negative step.
@@ -258,9 +262,56 @@
containing 'yield' to be factored out and placed in another generator.
Additionally, the subgenerator is allowed to return with a value, and the
value is made available to the delegating generator.
+
While designed primarily for use in delegating to a subgenerator, the ``yield
from`` expression actually allows delegation to arbitrary subiterators.

+For simple iterators, ``yield from iterable`` is essentially just a shortened
+form of ``for item in iterable: yield item``::
+
+ >>> def g(x):
+ ... yield from range(x, 0, -1)
+ ... yield from range(x)
+ ...
+ >>> list(g(5))
+ [5, 4, 3, 2, 1, 0, 1, 2, 3, 4]
+
+However, unlike an ordinary loop, ``yield from`` allows subgenerators to
+receive sent and thrown values directly from the calling scope, and
+return a final value to the outer generator::
+
+ >>> def accumulate(start=0):
+ ... tally = start
+ ... while 1:
+ ... next = yield
+ ... if next is None:
+ ... return tally
+ ... tally += next
+ ...
+ >>> def gather_tallies(tallies, start=0):
+ ... while 1:
+ ... tally = yield from accumulate()
+ ... tallies.append(tally)
+ ...
+ >>> tallies = []
+ >>> acc = gather_tallies(tallies)
+ >>> next(acc) # Ensure the accumulator is ready to accept values
+ >>> for i in range(10):
+ ... acc.send(i)
+ ...
+ >>> acc.send(None) # Finish the first tally
+ >>> for i in range(5):
+ ... acc.send(i)
+ ...
+ >>> acc.send(None) # Finish the second tally
+ >>> tallies
+ [45, 10]
+
+The main principle driving this change is to allow even generators that are
+designed to be used with the ``send`` and ``throw`` methods to be split into
+multiple subgenerators as easily as a single large function can be split into
+multiple subfunctions.
+
(Implementation by Greg Ewing, integrated into 3.3 by Renaud Blanch, Ryan
Kelly and Nick Coghlan, documentation by Zbigniew Jędrzejewski-Szmek and
Nick Coghlan)
@@ -327,6 +378,21 @@
KeyError('x',)


+PEP 414: Explicit Unicode literals
+======================================
+
+:pep:`414` - Explicit Unicode literals
+ PEP written by Armin Ronacher.
+
+To ease the transition from Python 2 for Unicode aware Python applications
+that make heavy use of Unicode literals, Python 3.3 once again supports the
+"``u``" prefix for string literals. This prefix has no semantic significance
+in Python 3, it is provided solely to reduce the number of purely mechanical
+changes in migrating to Python 3, making it easier for developers to focus on
+the more significant semantic changes (such as the stricter default
+separation of binary and text data).
+
+
PEP 3155: Qualified name for classes and functions
==================================================

@@ -408,10 +474,6 @@

(:issue:`12170`)

-* Memoryview objects are now hashable when the underlying object is hashable.
-
- (Contributed by Antoine Pitrou in :issue:`13411`)
-

New and Improved Modules
========================

--
Repository URL: http://hg.python.org/cpython
cpython (merge default -> default): Merge [ In reply to ]
http://hg.python.org/cpython/rev/b154ab2cdb1e
changeset: 75551:b154ab2cdb1e
parent: 75550:06628ec43732
parent: 75549:8538eeb71698
user: Michael Foord <michael@voidspace.org.uk>
date: Mon Mar 12 13:54:03 2012 -0700
summary:
Merge

files:
Lib/pickle.py | 8 ++++++++
Lib/test/pickletester.py | 12 ++++++++++++
Lib/test/test_sys.py | 2 +-
Misc/ACKS | 1 +
Modules/_pickle.c | 21 +++++++++++++++++++++
5 files changed, 43 insertions(+), 1 deletions(-)


diff --git a/Lib/pickle.py b/Lib/pickle.py
--- a/Lib/pickle.py
+++ b/Lib/pickle.py
@@ -438,6 +438,14 @@
self.write(NONE)
dispatch[type(None)] = save_none

+ def save_ellipsis(self, obj):
+ self.save_global(Ellipsis, 'Ellipsis')
+ dispatch[type(Ellipsis)] = save_ellipsis
+
+ def save_notimplemented(self, obj):
+ self.save_global(NotImplemented, 'NotImplemented')
+ dispatch[type(NotImplemented)] = save_notimplemented
+
def save_bool(self, obj):
if self.proto >= 2:
self.write(obj and NEWTRUE or NEWFALSE)
diff --git a/Lib/test/pickletester.py b/Lib/test/pickletester.py
--- a/Lib/test/pickletester.py
+++ b/Lib/test/pickletester.py
@@ -743,6 +743,18 @@
u = self.loads(s)
self.assertEqual(t, u)

+ def test_ellipsis(self):
+ for proto in protocols:
+ s = self.dumps(..., proto)
+ u = self.loads(s)
+ self.assertEqual(..., u)
+
+ def test_notimplemented(self):
+ for proto in protocols:
+ s = self.dumps(NotImplemented, proto)
+ u = self.loads(s)
+ self.assertEqual(NotImplemented, u)
+
# Tests for protocol 2

def test_proto(self):
diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py
--- a/Lib/test/test_sys.py
+++ b/Lib/test/test_sys.py
@@ -882,7 +882,7 @@
check = self.check_sizeof
# _ast.AST
import _ast
- check(_ast.AST(), size(h + ''))
+ check(_ast.AST(), size(h + 'P'))
# imp.NullImporter
import imp
check(imp.NullImporter(self.file.name), size(h + ''))
diff --git a/Misc/ACKS b/Misc/ACKS
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -883,6 +883,7 @@
Rich Salz
Kevin Samborn
Adrian Sampson
+James Sanders
Ilya Sandler
Mark Sapiro
Ty Sarna
diff --git a/Modules/_pickle.c b/Modules/_pickle.c
--- a/Modules/_pickle.c
+++ b/Modules/_pickle.c
@@ -2812,6 +2812,19 @@
}

static int
+save_ellipsis(PicklerObject *self, PyObject *obj)
+{
+ return save_global(self, Py_Ellipsis, PyUnicode_FromString("Ellipsis"));
+}
+
+static int
+save_notimplemented(PicklerObject *self, PyObject *obj)
+{
+ return save_global(self, Py_NotImplemented,
+ PyUnicode_FromString("NotImplemented"));
+}
+
+static int
save_pers(PicklerObject *self, PyObject *obj, PyObject *func)
{
PyObject *pid = NULL;
@@ -3114,6 +3127,14 @@
status = save_none(self, obj);
goto done;
}
+ else if (obj == Py_Ellipsis) {
+ status = save_ellipsis(self, obj);
+ goto done;
+ }
+ else if (obj == Py_NotImplemented) {
+ status = save_notimplemented(self, obj);
+ goto done;
+ }
else if (obj == Py_False || obj == Py_True) {
status = save_bool(self, obj);
goto done;

--
Repository URL: http://hg.python.org/cpython
cpython (merge default -> default): Merge [ In reply to ]
http://hg.python.org/cpython/rev/e04750e0ffd6
changeset: 75557:e04750e0ffd6
parent: 75556:8c5506468ecb
parent: 75555:9cccfaa6b534
user: Michael Foord <michael@voidspace.org.uk>
date: Mon Mar 12 15:25:12 2012 -0700
summary:
Merge

files:
Lib/aifc.py | 12 +-
Lib/test/test_aifc.py | 158 ++++++++++++++++++++++++++++-
Misc/NEWS | 2 +
Modules/_pickle.c | 11 +-
4 files changed, 165 insertions(+), 18 deletions(-)


diff --git a/Lib/aifc.py b/Lib/aifc.py
--- a/Lib/aifc.py
+++ b/Lib/aifc.py
@@ -136,6 +136,7 @@

import struct
import builtins
+import warnings

__all__ = ["Error", "open", "openfp"]

@@ -440,7 +441,7 @@
kludge = 0
if chunk.chunksize == 18:
kludge = 1
- print('Warning: bad COMM chunk size')
+ warnings.warn('Warning: bad COMM chunk size')
chunk.chunksize = 23
#DEBUG end
self._comptype = chunk.read(4)
@@ -484,11 +485,10 @@
# a position 0 and name ''
self._markers.append((id, pos, name))
except EOFError:
- print('Warning: MARK chunk contains only', end=' ')
- print(len(self._markers), end=' ')
- if len(self._markers) == 1: print('marker', end=' ')
- else: print('markers', end=' ')
- print('instead of', nmarkers)
+ w = ('Warning: MARK chunk contains only %s marker%s instead of %s' %
+ (len(self._markers), '' if len(self._markers) == 1 else 's',
+ nmarkers))
+ warnings.warn(w)

class Aifc_write:
# Variables used in this class:
diff --git a/Lib/test/test_aifc.py b/Lib/test/test_aifc.py
--- a/Lib/test/test_aifc.py
+++ b/Lib/test/test_aifc.py
@@ -1,7 +1,8 @@
-from test.support import findfile, run_unittest, TESTFN
+from test.support import findfile, run_unittest, TESTFN, unlink
import unittest
import os
import io
+import struct

import aifc

@@ -20,10 +21,8 @@
self.fout.close()
except (aifc.Error, AttributeError):
pass
- try:
- os.remove(TESTFN)
- except OSError:
- pass
+ unlink(TESTFN)
+ unlink(TESTFN + '.aiff')

def test_skipunknown(self):
#Issue 2245
@@ -32,6 +31,7 @@

def test_params(self):
f = self.f = aifc.open(self.sndfilepath)
+ self.assertEqual(f.getfp().name, self.sndfilepath)
self.assertEqual(f.getnchannels(), 2)
self.assertEqual(f.getsampwidth(), 2)
self.assertEqual(f.getframerate(), 48000)
@@ -45,6 +45,7 @@

def test_read(self):
f = self.f = aifc.open(self.sndfilepath)
+ self.assertEqual(f.readframes(0), b'')
self.assertEqual(f.tell(), 0)
self.assertEqual(f.readframes(2), b'\x00\x00\x00\x00\x0b\xd4\x0b\xd4')
f.rewind()
@@ -58,6 +59,10 @@
self.assertEqual(f.readframes(2), b'\x17t\x17t"\xad"\xad')
f.setpos(pos0)
self.assertEqual(f.readframes(2), b'\x00\x00\x00\x00\x0b\xd4\x0b\xd4')
+ with self.assertRaises(aifc.Error):
+ f.setpos(-1)
+ with self.assertRaises(aifc.Error):
+ f.setpos(f.getnframes() + 1)

def test_write(self):
f = self.f = aifc.open(self.sndfilepath)
@@ -92,8 +97,6 @@
self.assertEqual(f.getparams()[0:3], fout.getparams()[0:3])
self.assertEqual(fout.getcomptype(), b'ULAW')
self.assertEqual(fout.getcompname(), b'foo')
- # XXX: this test fails, not sure if it should succeed or not
- # self.assertEqual(f.readframes(5), fout.readframes(5))

def test_close(self):
class Wrapfile(object):
@@ -112,7 +115,7 @@

def test_write_header_comptype_sampwidth(self):
for comptype in (b'ULAW', b'ulaw', b'ALAW', b'alaw', b'G722'):
- fout = self.fout = aifc.open(io.BytesIO(), 'wb')
+ fout = aifc.open(io.BytesIO(), 'wb')
fout.setnchannels(1)
fout.setframerate(1)
fout.setcomptype(comptype, b'')
@@ -121,7 +124,7 @@
fout.initfp(None)

def test_write_markers_values(self):
- fout = self.fout = aifc.open(io.BytesIO(), 'wb')
+ fout = aifc.open(io.BytesIO(), 'wb')
self.assertEqual(fout.getmarkers(), None)
fout.setmark(1, 0, b'foo1')
fout.setmark(1, 1, b'foo2')
@@ -179,6 +182,143 @@
with self.assertRaises(ValueError):
aifc._write_string(f, b'too long' * 255)

+ def test_wrong_open_mode(self):
+ with self.assertRaises(aifc.Error):
+ aifc.open(TESTFN, 'wrong_mode')
+
+ def test_read_wrong_form(self):
+ b1 = io.BytesIO(b'WRNG' + struct.pack('>L', 0))
+ b2 = io.BytesIO(b'FORM' + struct.pack('>L', 4) + b'WRNG')
+ self.assertRaises(aifc.Error, aifc.open, b1)
+ self.assertRaises(aifc.Error, aifc.open, b2)
+
+ def test_read_no_comm_chunk(self):
+ b = io.BytesIO(b'FORM' + struct.pack('>L', 4) + b'AIFF')
+ self.assertRaises(aifc.Error, aifc.open, b)
+
+ def test_read_wrong_compression_type(self):
+ b = b'FORM' + struct.pack('>L', 4) + b'AIFC'
+ b += b'COMM' + struct.pack('>LhlhhLL', 23, 0, 0, 0, 0, 0, 0)
+ b += b'WRNG' + struct.pack('B', 0)
+ self.assertRaises(aifc.Error, aifc.open, io.BytesIO(b))
+
+ def test_read_wrong_marks(self):
+ b = b'FORM' + struct.pack('>L', 4) + b'AIFF'
+ b += b'COMM' + struct.pack('>LhlhhLL', 18, 0, 0, 0, 0, 0, 0)
+ b += b'SSND' + struct.pack('>L', 8) + b'\x00' * 8
+ b += b'MARK' + struct.pack('>LhB', 3, 1, 1)
+ with self.assertWarns(UserWarning):
+ f = aifc.open(io.BytesIO(b))
+ self.assertEqual(f.getmarkers(), None)
+
+ def test_read_comm_kludge_compname_even(self):
+ b = b'FORM' + struct.pack('>L', 4) + b'AIFC'
+ b += b'COMM' + struct.pack('>LhlhhLL', 18, 0, 0, 0, 0, 0, 0)
+ b += b'NONE' + struct.pack('B', 4) + b'even' + b'\x00'
+ b += b'SSND' + struct.pack('>L', 8) + b'\x00' * 8
+ with self.assertWarns(UserWarning):
+ f = aifc.open(io.BytesIO(b))
+ self.assertEqual(f.getcompname(), b'even')
+
+ def test_read_comm_kludge_compname_odd(self):
+ b = b'FORM' + struct.pack('>L', 4) + b'AIFC'
+ b += b'COMM' + struct.pack('>LhlhhLL', 18, 0, 0, 0, 0, 0, 0)
+ b += b'NONE' + struct.pack('B', 3) + b'odd'
+ b += b'SSND' + struct.pack('>L', 8) + b'\x00' * 8
+ with self.assertWarns(UserWarning):
+ f = aifc.open(io.BytesIO(b))
+ self.assertEqual(f.getcompname(), b'odd')
+
+ def test_write_params_raises(self):
+ fout = aifc.open(io.BytesIO(), 'wb')
+ wrong_params = (0, 0, 0, 0, b'WRNG', '')
+ self.assertRaises(aifc.Error, fout.setparams, wrong_params)
+ self.assertRaises(aifc.Error, fout.getparams)
+ self.assertRaises(aifc.Error, fout.setnchannels, 0)
+ self.assertRaises(aifc.Error, fout.getnchannels)
+ self.assertRaises(aifc.Error, fout.setsampwidth, 0)
+ self.assertRaises(aifc.Error, fout.getsampwidth)
+ self.assertRaises(aifc.Error, fout.setframerate, 0)
+ self.assertRaises(aifc.Error, fout.getframerate)
+ self.assertRaises(aifc.Error, fout.setcomptype, b'WRNG', '')
+ fout.aiff()
+ fout.setnchannels(1)
+ fout.setsampwidth(1)
+ fout.setframerate(1)
+ fout.setnframes(1)
+ fout.writeframes(b'\x00')
+ self.assertRaises(aifc.Error, fout.setparams, (1, 1, 1, 1, 1, 1))
+ self.assertRaises(aifc.Error, fout.setnchannels, 1)
+ self.assertRaises(aifc.Error, fout.setsampwidth, 1)
+ self.assertRaises(aifc.Error, fout.setframerate, 1)
+ self.assertRaises(aifc.Error, fout.setnframes, 1)
+ self.assertRaises(aifc.Error, fout.setcomptype, b'NONE', '')
+ self.assertRaises(aifc.Error, fout.aiff)
+ self.assertRaises(aifc.Error, fout.aifc)
+
+ def test_write_params_singles(self):
+ fout = aifc.open(io.BytesIO(), 'wb')
+ fout.aifc()
+ fout.setnchannels(1)
+ fout.setsampwidth(2)
+ fout.setframerate(3)
+ fout.setnframes(4)
+ fout.setcomptype(b'NONE', b'name')
+ self.assertEqual(fout.getnchannels(), 1)
+ self.assertEqual(fout.getsampwidth(), 2)
+ self.assertEqual(fout.getframerate(), 3)
+ self.assertEqual(fout.getnframes(), 0)
+ self.assertEqual(fout.tell(), 0)
+ self.assertEqual(fout.getcomptype(), b'NONE')
+ self.assertEqual(fout.getcompname(), b'name')
+ fout.writeframes(b'\x00' * 4 * fout.getsampwidth() * fout.getnchannels())
+ self.assertEqual(fout.getnframes(), 4)
+ self.assertEqual(fout.tell(), 4)
+
+ def test_write_params_bunch(self):
+ fout = aifc.open(io.BytesIO(), 'wb')
+ fout.aifc()
+ p = (1, 2, 3, 4, b'NONE', b'name')
+ fout.setparams(p)
+ self.assertEqual(fout.getparams(), p)
+ fout.initfp(None)
+
+ def test_write_header_raises(self):
+ fout = aifc.open(io.BytesIO(), 'wb')
+ self.assertRaises(aifc.Error, fout.close)
+ fout.setnchannels(1)
+ self.assertRaises(aifc.Error, fout.close)
+ fout.setsampwidth(1)
+ self.assertRaises(aifc.Error, fout.close)
+ fout.initfp(None)
+
+ def test_write_header_comptype_raises(self):
+ for comptype in (b'ULAW', b'ulaw', b'ALAW', b'alaw', b'G722'):
+ fout = aifc.open(io.BytesIO(), 'wb')
+ fout.setsampwidth(1)
+ fout.setcomptype(comptype, b'')
+ self.assertRaises(aifc.Error, fout.close)
+ fout.initfp(None)
+
+ def test_write_markers_raises(self):
+ fout = aifc.open(io.BytesIO(), 'wb')
+ self.assertRaises(aifc.Error, fout.setmark, 0, 0, b'')
+ self.assertRaises(aifc.Error, fout.setmark, 1, -1, b'')
+ self.assertRaises(aifc.Error, fout.setmark, 1, 0, None)
+ self.assertRaises(aifc.Error, fout.getmark, 1)
+ fout.initfp(None)
+
+ def test_write_aiff_by_extension(self):
+ sampwidth = 2
+ fout = self.fout = aifc.open(TESTFN + '.aiff', 'wb')
+ fout.setparams((1, sampwidth, 1, 1, b'ULAW', b''))
+ frames = b'\x00' * fout.getnchannels() * sampwidth
+ fout.writeframes(frames)
+ fout.close()
+ f = self.f = aifc.open(TESTFN + '.aiff', 'rb')
+ self.assertEqual(f.getcomptype(), b'NONE')
+ f.close()
+

def test_main():
run_unittest(AIFCTest)
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -24,6 +24,8 @@
Library
-------

+- Issue #13394: the aifc module now uses warnings.warn() to signal warnings.
+
- Issue #14252: Fix subprocess.Popen.terminate() to not raise an error under
Windows when the child process has already exited.

diff --git a/Modules/_pickle.c b/Modules/_pickle.c
--- a/Modules/_pickle.c
+++ b/Modules/_pickle.c
@@ -2814,14 +2814,19 @@
static int
save_ellipsis(PicklerObject *self, PyObject *obj)
{
- return save_global(self, Py_Ellipsis, PyUnicode_FromString("Ellipsis"));
+ PyObject *str = PyUnicode_FromString("Ellipsis");
+ if (str == NULL)
+ return -1;
+ return save_global(self, Py_Ellipsis, str);
}

static int
save_notimplemented(PicklerObject *self, PyObject *obj)
{
- return save_global(self, Py_NotImplemented,
- PyUnicode_FromString("NotImplemented"));
+ PyObject *str = PyUnicode_FromString("NotImplemented");
+ if (str == NULL)
+ return -1;
+ return save_global(self, Py_NotImplemented, str);
}

static int

--
Repository URL: http://hg.python.org/cpython
cpython (merge default -> default): Merge [ In reply to ]
http://hg.python.org/cpython/rev/4925efb9f9f6
changeset: 75637:4925efb9f9f6
parent: 75636:6493f091b401
parent: 75635:a7a9e0f46b8a
user: Michael Foord <michael@voidspace.org.uk>
date: Wed Mar 14 12:59:08 2012 -0700
summary:
Merge

files:
Modules/tkappinit.c | 6 ++++++
1 files changed, 6 insertions(+), 0 deletions(-)


diff --git a/Modules/tkappinit.c b/Modules/tkappinit.c
--- a/Modules/tkappinit.c
+++ b/Modules/tkappinit.c
@@ -26,7 +26,9 @@
int
Tcl_AppInit(Tcl_Interp *interp)
{
+#ifdef WITH_MOREBUTTONS
Tk_Window main_window;
+#endif
const char *_tkinter_skip_tk_init;
#ifdef TKINTER_PROTECT_LOADTK
const char *_tkinter_tk_failed;
@@ -111,7 +113,11 @@
return TCL_ERROR;
}

+#ifdef WITH_MOREBUTTONS
main_window = Tk_MainWindow(interp);
+#else
+ Tk_MainWindow(interp);
+#endif

#ifdef TK_AQUA
TkMacOSXInitAppleEvents(interp);

--
Repository URL: http://hg.python.org/cpython
cpython (merge default -> default): merge [ In reply to ]
http://hg.python.org/cpython/rev/b86b414673c3
changeset: 75685:b86b414673c3
parent: 75684:0ddb78341290
parent: 75683:dcf39147deeb
user: Raymond Hettinger <python@rcn.com>
date: Wed Mar 14 18:17:20 2012 -0700
summary:
merge

files:
Doc/howto/urllib2.rst | 4 +++-
Doc/library/urllib.request.rst | 17 ++++++++---------
Modules/expat/expat.h | 2 ++
Modules/pyexpat.c | 5 +++++
4 files changed, 18 insertions(+), 10 deletions(-)


diff --git a/Doc/howto/urllib2.rst b/Doc/howto/urllib2.rst
--- a/Doc/howto/urllib2.rst
+++ b/Doc/howto/urllib2.rst
@@ -115,6 +115,7 @@
'language' : 'Python' }

data = urllib.parse.urlencode(values)
+ data = data.encode('utf-8') # data should be bytes
req = urllib.request.Request(url, data)
response = urllib.request.urlopen(req)
the_page = response.read()
@@ -179,7 +180,8 @@
'language' : 'Python' }
headers = { 'User-Agent' : user_agent }

- data = urllib.parse.urlencode(values)
+ data = urllib.parse.urlencode(values)
+ data = data.encode('utf-8')
req = urllib.request.Request(url, data, headers)
response = urllib.request.urlopen(req)
the_page = response.read()
diff --git a/Doc/library/urllib.request.rst b/Doc/library/urllib.request.rst
--- a/Doc/library/urllib.request.rst
+++ b/Doc/library/urllib.request.rst
@@ -138,14 +138,13 @@

*url* should be a string containing a valid URL.

- *data* may be a string specifying additional data to send to the
- server, or ``None`` if no such data is needed. Currently HTTP
- requests are the only ones that use *data*, in order to choose between
- ``'GET'`` and ``'POST'`` when *method* is not specified.
- *data* should be a buffer in the standard
- :mimetype:`application/x-www-form-urlencoded` format. The
- :func:`urllib.parse.urlencode` function takes a mapping or sequence
- of 2-tuples and returns a string in this format.
+ *data* may be a bytes object specifying additional data to send to the
+ server, or ``None`` if no such data is needed. Currently HTTP requests are
+ the only ones that use *data*; the HTTP request will be a POST instead of a
+ GET when the *data* parameter is provided. *data* should be a buffer in the
+ standard :mimetype:`application/x-www-form-urlencoded` format. The
+ :func:`urllib.parse.urlencode` function takes a mapping or sequence of
+ 2-tuples and returns a string in this format.

*headers* should be a dictionary, and will be treated as if
:meth:`add_header` was called with each key and value as arguments.
@@ -1183,7 +1182,7 @@

If the *url* uses the :file:`http:` scheme identifier, the optional *data*
argument may be given to specify a ``POST`` request (normally the request
- type is ``GET``). The *data* argument must in standard
+ type is ``GET``). The *data* argument must be a bytes object in standard
:mimetype:`application/x-www-form-urlencoded` format; see the
:func:`urlencode` function below.

diff --git a/Modules/expat/expat.h b/Modules/expat/expat.h
--- a/Modules/expat/expat.h
+++ b/Modules/expat/expat.h
@@ -892,6 +892,8 @@
XML_SetHashSalt(XML_Parser parser,
unsigned long hash_salt);

+#define XML_HAS_SET_HASH_SALT /* Python Only: Defined for pyexpat.c. */
+
/* If XML_Parse or XML_ParseBuffer have returned XML_STATUS_ERROR, then
XML_GetErrorCode returns information about the error.
*/
diff --git a/Modules/pyexpat.c b/Modules/pyexpat.c
--- a/Modules/pyexpat.c
+++ b/Modules/pyexpat.c
@@ -1156,8 +1156,13 @@
else {
self->itself = XML_ParserCreate(encoding);
}
+#if ((XML_MAJOR_VERSION >= 2) && (XML_MINOR_VERSION >= 1)) || defined(XML_HAS_SET_HASH_SALT)
+ /* This feature was added upstream in libexpat 2.1.0. Our expat copy
+ * has a backport of this feature where we also define XML_HAS_SET_HASH_SALT
+ * to indicate that we can still use it. */
XML_SetHashSalt(self->itself,
(unsigned long)_Py_HashSecret.prefix);
+#endif
self->intern = intern;
Py_XINCREF(self->intern);
PyObject_GC_Track(self);

--
Repository URL: http://hg.python.org/cpython
cpython (merge default -> default): merge [ In reply to ]
http://hg.python.org/cpython/rev/870c0ef7e8a2
changeset: 75730:870c0ef7e8a2
parent: 75729:3b2856d8614b
parent: 75728:13c44ad094b4
user: Raymond Hettinger <python@rcn.com>
date: Fri Mar 16 01:18:33 2012 -0700
summary:
merge

files:
Lib/http/server.py | 9 ++++++++-
Lib/test/test_httpservers.py | 1 +
Misc/NEWS | 2 ++
3 files changed, 11 insertions(+), 1 deletions(-)


diff --git a/Lib/http/server.py b/Lib/http/server.py
--- a/Lib/http/server.py
+++ b/Lib/http/server.py
@@ -865,7 +865,14 @@
# Filter out blank non trailing parts before consuming the '..'.
path_parts = [part for part in path_parts[:-1] if part] + path_parts[-1:]
if path_parts:
- tail_part = path_parts.pop()
+ # Special case for CGI's for PATH_INFO
+ if path.startswith('/cgi-bin') or path.startswith('/htbin'):
+ tail_part = []
+ while path_parts[-1] not in ('cgi-bin','htbin'):
+ tail_part.insert(0,path_parts.pop())
+ tail_part = "/".join(tail_part)
+ else:
+ tail_part = path_parts.pop()
else:
tail_part = ''
head_parts = []
diff --git a/Lib/test/test_httpservers.py b/Lib/test/test_httpservers.py
--- a/Lib/test/test_httpservers.py
+++ b/Lib/test/test_httpservers.py
@@ -377,6 +377,7 @@
'/.//': ('/', ''),
'cgi-bin/file1.py': ('/cgi-bin', 'file1.py'),
'/cgi-bin/file1.py': ('/cgi-bin', 'file1.py'),
+ '/cgi-bin/file1.py/PATH-INFO': ('/cgi-bin', 'file1.py/PATH-INFO'),
'a': ('/', 'a'),
'/a': ('/', 'a'),
'//a': ('/', 'a'),
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -24,6 +24,8 @@
Library
-------

+- Issue #10484: Fix the CGIHTTPServer's PATH_INFO handling problem.
+
- Issue #11199: Fix the with urllib which hangs on particular ftp urls.

- Improve the memory utilization and speed of functools.lru_cache.

--
Repository URL: http://hg.python.org/cpython
cpython (merge default -> default): Merge [ In reply to ]
http://hg.python.org/cpython/rev/fb76bb09ad0f
changeset: 75755:fb76bb09ad0f
parent: 75754:b2a8310de718
parent: 75753:13e2d09e0612
user: Antoine Pitrou <solipsis@pitrou.net>
date: Sat Mar 17 00:24:12 2012 +0100
summary:
Merge

files:
Lib/functools.py | 4 +++-
1 files changed, 3 insertions(+), 1 deletions(-)


diff --git a/Lib/functools.py b/Lib/functools.py
--- a/Lib/functools.py
+++ b/Lib/functools.py
@@ -226,9 +226,11 @@

def cache_clear():
"""Clear the cache and cache statistics"""
- nonlocal hits, misses
+ nonlocal hits, misses, root
with lock:
cache.clear()
+ root = []
+ root[:] = [root, root, None, None]
hits = misses = 0

wrapper.cache_info = cache_info

--
Repository URL: http://hg.python.org/cpython
cpython (merge default -> default): merge [ In reply to ]
http://hg.python.org/cpython/rev/669893133f9f
changeset: 75896:669893133f9f
parent: 75895:e35a5bbb0b91
parent: 75894:75268a773455
user: Giampaolo Rodola' <g.rodola@gmail.com>
date: Fri Mar 23 13:29:49 2012 +0100
summary:
merge

files:
Doc/library/xml.etree.elementtree.rst | 12 +++++++-----
Lib/test/test_xml_etree.py | 12 +++++++++---
Lib/xml/etree/ElementTree.py | 12 ++++++++----
Modules/_elementtree.c | 9 +++++++++
4 files changed, 33 insertions(+), 12 deletions(-)


diff --git a/Doc/library/xml.etree.elementtree.rst b/Doc/library/xml.etree.elementtree.rst
--- a/Doc/library/xml.etree.elementtree.rst
+++ b/Doc/library/xml.etree.elementtree.rst
@@ -281,14 +281,15 @@

.. method:: append(subelement)

- Adds the element *subelement* to the end of this elements internal list
- of subelements.
+ Adds the element *subelement* to the end of this element's internal list
+ of subelements. Raises :exc:`TypeError` if *subelement* is not an
+ :class:`Element`.


.. method:: extend(subelements)

Appends *subelements* from a sequence object with zero or more elements.
- Raises :exc:`AssertionError` if a subelement is not a valid object.
+ Raises :exc:`TypeError` if a subelement is not an :class:`Element`.

.. versionadded:: 3.2

@@ -325,9 +326,10 @@
Use method :meth:`Element.iter` instead.


- .. method:: insert(index, element)
+ .. method:: insert(index, subelement)

- Inserts a subelement at the given position in this element.
+ Inserts *subelement* at the given position in this element. Raises
+ :exc:`TypeError` if *subelement* is not an :class:`Element`.


.. method:: iter(tag=None)
diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py
--- a/Lib/test/test_xml_etree.py
+++ b/Lib/test/test_xml_etree.py
@@ -1839,8 +1839,15 @@
# --------------------------------------------------------------------


+class BasicElementTest(unittest.TestCase):
+ def test_augmentation_type_errors(self):
+ e = ET.Element('joe')
+ self.assertRaises(TypeError, e.append, 'b')
+ self.assertRaises(TypeError, e.extend, [ET.Element('bar'), 'foo'])
+ self.assertRaises(TypeError, e.insert, 0, 'foo')
+
+
class ElementTreeTest(unittest.TestCase):
-
def test_istype(self):
self.assertIsInstance(ET.ParseError, type)
self.assertIsInstance(ET.QName, type)
@@ -1879,7 +1886,6 @@


class TreeBuilderTest(unittest.TestCase):
-
sample1 = ('<!DOCTYPE html PUBLIC'
' "-//W3C//DTD XHTML 1.0 Transitional//EN"'
' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'
@@ -1931,7 +1937,6 @@


class NoAcceleratorTest(unittest.TestCase):
-
# Test that the C accelerator was not imported for pyET
def test_correct_import_pyET(self):
self.assertEqual(pyET.Element.__module__, 'xml.etree.ElementTree')
@@ -2096,6 +2101,7 @@

test_classes = [
ElementSlicingTest,
+ BasicElementTest,
StringIOTest,
ParseErrorTest,
ElementTreeTest,
diff --git a/Lib/xml/etree/ElementTree.py b/Lib/xml/etree/ElementTree.py
--- a/Lib/xml/etree/ElementTree.py
+++ b/Lib/xml/etree/ElementTree.py
@@ -298,7 +298,7 @@
# @param element The element to add.

def append(self, element):
- # assert iselement(element)
+ self._assert_is_element(element)
self._children.append(element)

##
@@ -308,8 +308,8 @@
# @since 1.3

def extend(self, elements):
- # for element in elements:
- # assert iselement(element)
+ for element in elements:
+ self._assert_is_element(element)
self._children.extend(elements)

##
@@ -318,9 +318,13 @@
# @param index Where to insert the new subelement.

def insert(self, index, element):
- # assert iselement(element)
+ self._assert_is_element(element)
self._children.insert(index, element)

+ def _assert_is_element(self, e):
+ if not isinstance(e, Element):
+ raise TypeError('expected an Element, not %s' % type(e).__name__)
+
##
# Removes a matching subelement. Unlike the <b>find</b> methods,
# this method compares elements based on identity, not on tag
diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c
--- a/Modules/_elementtree.c
+++ b/Modules/_elementtree.c
@@ -803,6 +803,15 @@
seqlen = PySequence_Size(seq);
for (i = 0; i < seqlen; i++) {
PyObject* element = PySequence_Fast_GET_ITEM(seq, i);
+ if (!PyObject_IsInstance(element, (PyObject *)&Element_Type)) {
+ Py_DECREF(seq);
+ PyErr_Format(
+ PyExc_TypeError,
+ "expected an Element, not \"%.200s\"",
+ Py_TYPE(element)->tp_name);
+ return NULL;
+ }
+
if (element_add_subelement(self, element) < 0) {
Py_DECREF(seq);
return NULL;

--
Repository URL: http://hg.python.org/cpython
cpython (merge default -> default): Merge [ In reply to ]
http://hg.python.org/cpython/rev/28183f010a05
changeset: 75925:28183f010a05
parent: 75924:bd52c8331dac
parent: 75923:0ed7da703a33
user: Michael Foord <michael@voidspace.org.uk>
date: Sun Mar 25 18:16:26 2012 +0100
summary:
Merge

files:
Lib/test/test_decimal.py | 2 +-
Modules/_decimal/_decimal.c | 9 ++++++++-
2 files changed, 9 insertions(+), 2 deletions(-)


diff --git a/Lib/test/test_decimal.py b/Lib/test/test_decimal.py
--- a/Lib/test/test_decimal.py
+++ b/Lib/test/test_decimal.py
@@ -3837,7 +3837,7 @@

x = dir(C)
y = [.s for s in dir(P) if '__' in s or not s.startswith('_')]
- self.assertEqual(set(x) - set(y), {'MallocError'})
+ self.assertEqual(set(x) - set(y), set())

def test_context_attributes(self):

diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c
--- a/Modules/_decimal/_decimal.c
+++ b/Modules/_decimal/_decimal.c
@@ -168,7 +168,9 @@
{"DivisionImpossible", "decimal.DivisionImpossible", MPD_Division_impossible, NULL},
{"DivisionUndefined", "decimal.DivisionUndefined", MPD_Division_undefined, NULL},
{"InvalidContext", "decimal.InvalidContext", MPD_Invalid_context, NULL},
+#ifdef EXTRA_FUNCTIONALITY
{"MallocError", "decimal.MallocError", MPD_Malloc_error, NULL},
+#endif
{NULL}
};

@@ -466,9 +468,14 @@
mpd_context_t *ctx = CTX(context);

ctx->status |= status;
- if (ctx->traps&status) {
+ if (status & (ctx->traps|MPD_Malloc_error)) {
PyObject *ex, *siglist;

+ if (status & MPD_Malloc_error) {
+ PyErr_NoMemory();
+ return 1;
+ }
+
ex = flags_as_exception(ctx->traps&status);
if (ex == NULL) {
return 1; /* GCOV_NOT_REACHED */

--
Repository URL: http://hg.python.org/cpython
cpython (merge default -> default): merge [ In reply to ]
http://hg.python.org/cpython/rev/d0e4e3ef224e
changeset: 76082:d0e4e3ef224e
parent: 76081:a40cd5976215
parent: 76080:8ba72c0987dc
user: Brett Cannon <brett@python.org>
date: Mon Apr 02 20:34:20 2012 -0400
summary:
merge

files:
Doc/library/time.rst | 16 +++++
Lib/test/test_decimal.py | 70 -------------------------
Lib/test/test_thread.py | 1 -
Lib/test/test_time.py | 11 +++
Modules/_decimal/_decimal.c | 10 +-
Modules/timemodule.c | 33 +++++++++++
6 files changed, 65 insertions(+), 76 deletions(-)


diff --git a/Doc/library/time.rst b/Doc/library/time.rst
--- a/Doc/library/time.rst
+++ b/Doc/library/time.rst
@@ -151,6 +151,13 @@
.. versionadded:: 3.3


+.. function:: clock_settime(clk_id, time)
+
+ Set the time of the specified clock *clk_id*.
+
+ .. versionadded:: 3.3
+
+
.. data:: CLOCK_REALTIME

System-wide real-time clock. Setting this clock requires appropriate
@@ -159,6 +166,15 @@
.. versionadded:: 3.3


+.. data:: CLOCK_HIGHRES
+
+ The Solaris OS has a CLOCK_HIGHRES timer that attempts to use an optimal
+ hardware source, and may give close to nanosecond resolution. CLOCK_HIGHRES
+ is the nonadjustable, high-resolution clock.
+
+ .. versionadded:: 3.3
+
+
.. data:: CLOCK_MONOTONIC

Clock that cannot be set and represents monotonic time since some
diff --git a/Lib/test/test_decimal.py b/Lib/test/test_decimal.py
--- a/Lib/test/test_decimal.py
+++ b/Lib/test/test_decimal.py
@@ -56,76 +56,6 @@
fractions = {C:cfractions, P:pfractions}
sys.modules['decimal'] = orig_sys_decimal

-############ RunFirst ############
-class RunFirst(unittest.TestCase):
-
- def setUp(self):
- self.save_default = self.decimal.DefaultContext.copy()
-
- def tearDown(self):
- DefaultContext = self.decimal.DefaultContext
-
- DefaultContext.prec = self.save_default.prec
- DefaultContext.rounding = self.save_default.rounding
- DefaultContext.Emax = self.save_default.Emax
- DefaultContext.Emin = self.save_default.Emin
- DefaultContext.capitals = self.save_default.capitals
- DefaultContext.clamp = self.save_default.clamp
- DefaultContext.flags = self.save_default.flags
- DefaultContext.traps = self.save_default.traps
-
- self.decimal.setcontext(self.decimal.DefaultContext)
-
- def test_00default_context(self):
- # The test depends on the fact that getcontext() is called
- # for the first time.
- DefaultContext = self.decimal.DefaultContext
- ROUND_05UP = self.decimal.ROUND_05UP
- Clamped = self.decimal.Clamped
- InvalidOperation = self.decimal.InvalidOperation
-
- DefaultContext.prec = 5001
- DefaultContext.rounding = ROUND_05UP
- DefaultContext.Emax = 10025
- DefaultContext.Emin = -10025
- DefaultContext.capitals = 0
- DefaultContext.clamp = 1
- DefaultContext.flags[InvalidOperation] = True
- DefaultContext.clear_traps()
- DefaultContext.traps[Clamped] = True
-
- # implicit initialization on first access
- c = self.decimal.getcontext()
-
- self.assertEqual(c.prec, 5001)
- self.assertEqual(c.rounding, ROUND_05UP)
- self.assertEqual(c.Emax, 10025)
- self.assertEqual(c.Emin, -10025)
- self.assertEqual(c.capitals, 0)
- self.assertEqual(c.clamp, 1)
- for k in c.flags:
- self.assertFalse(c.flags[k])
- for k in c.traps:
- if k is Clamped:
- self.assertTrue(c.traps[k])
- else:
- self.assertFalse(c.traps[k])
-
- # explicit initialization
- self.decimal.setcontext(DefaultContext)
- c = self.decimal.getcontext()
- for k in c.flags:
- self.assertFalse(c.flags[k])
-
-class CRunFirst(RunFirst):
- decimal = C
-class PyRunFirst(RunFirst):
- decimal = P
-if C:
- run_unittest(CRunFirst, PyRunFirst)
-else:
- run_unittest(PyRunFirst)
-############ END RunFirst ############

# Useful Test Constant
Signals = {
diff --git a/Lib/test/test_thread.py b/Lib/test/test_thread.py
--- a/Lib/test/test_thread.py
+++ b/Lib/test/test_thread.py
@@ -132,7 +132,6 @@
# See issue #14474
def task():
started.release()
- sys.stderr = stderr
raise SyntaxError
def mywrite(self, *args):
try:
diff --git a/Lib/test/test_time.py b/Lib/test/test_time.py
--- a/Lib/test/test_time.py
+++ b/Lib/test/test_time.py
@@ -47,6 +47,17 @@
self.assertGreater(res, 0.0)
self.assertLessEqual(res, 1.0)

+ @unittest.skipUnless(hasattr(time, 'clock_settime'),
+ 'need time.clock_settime()')
+ def test_clock_settime(self):
+ t = time.clock_gettime(time.CLOCK_REALTIME)
+ try:
+ time.clock_settime(time.CLOCK_REALTIME, t)
+ except PermissionError:
+ pass
+
+ self.assertRaises(OSError, time.clock_settime, time.CLOCK_MONOTONIC, 0)
+
def test_conversions(self):
self.assertEqual(time.ctime(self.t),
time.asctime(time.localtime(self.t)))
diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c
--- a/Modules/_decimal/_decimal.c
+++ b/Modules/_decimal/_decimal.c
@@ -1510,7 +1510,7 @@
#define CURRENT_CONTEXT_ADDR(ctx) \
ctx = CTX(current_context())

-/* Return current context, increment reference */
+/* Return a new reference to the current context */
static PyObject *
PyDec_GetCurrentContext(void)
{
@@ -1614,7 +1614,7 @@
ctx = CTX(_c_t_x_o_b_j); \
}

-/* Return current context, increment reference */
+/* Return a new reference to the current context */
static PyObject *
PyDec_GetCurrentContext(void)
{
@@ -1759,7 +1759,7 @@
0, /* tp_print */
(getattrfunc) 0, /* tp_getattr */
(setattrfunc) 0, /* tp_setattr */
- 0, /* tp_compare */
+ 0, /* tp_reserved */
(reprfunc) 0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
@@ -2699,7 +2699,7 @@


/******************************************************************************/
-/* Implicit conversions to Decimal */
+/* Implicit conversions to Decimal */
/******************************************************************************/

/* Try to convert PyObject v to a new PyDecObject conv. If the conversion
@@ -2796,7 +2796,7 @@


/******************************************************************************/
-/* Implicit conversions to Decimal for comparison */
+/* Implicit conversions to Decimal for comparison */
/******************************************************************************/

/* Convert rationals for comparison */
diff --git a/Modules/timemodule.c b/Modules/timemodule.c
--- a/Modules/timemodule.c
+++ b/Modules/timemodule.c
@@ -158,6 +158,33 @@
"clock_gettime(clk_id) -> floating point number\n\
\n\
Return the time of the specified clock clk_id.");
+
+static PyObject *
+time_clock_settime(PyObject *self, PyObject *args)
+{
+ clockid_t clk_id;
+ PyObject *obj;
+ struct timespec tp;
+ int ret;
+
+ if (!PyArg_ParseTuple(args, "iO:clock_settime", &clk_id, &obj))
+ return NULL;
+
+ if (_PyTime_ObjectToTimespec(obj, &tp.tv_sec, &tp.tv_nsec) == -1)
+ return NULL;
+
+ ret = clock_settime((clockid_t)clk_id, &tp);
+ if (ret != 0) {
+ PyErr_SetFromErrno(PyExc_IOError);
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(clock_settime_doc,
+"clock_settime(clk_id, time)\n\
+\n\
+Set the time of the specified clock clk_id.");
#endif

#ifdef HAVE_CLOCK_GETRES
@@ -962,6 +989,9 @@
#ifdef CLOCK_MONOTONIC_RAW
PyModule_AddIntMacro(m, CLOCK_MONOTONIC_RAW);
#endif
+#ifdef CLOCK_HIGHRES
+ PyModule_AddIntMacro(m, CLOCK_HIGHRES);
+#endif
#ifdef CLOCK_PROCESS_CPUTIME_ID
PyModule_AddIntMacro(m, CLOCK_PROCESS_CPUTIME_ID);
#endif
@@ -980,6 +1010,9 @@
#ifdef HAVE_CLOCK_GETTIME
{"clock_gettime", time_clock_gettime, METH_VARARGS, clock_gettime_doc},
#endif
+#ifdef HAVE_CLOCK_GETTIME
+ {"clock_settime", time_clock_settime, METH_VARARGS, clock_settime_doc},
+#endif
#ifdef HAVE_CLOCK_GETRES
{"clock_getres", time_clock_getres, METH_VARARGS, clock_getres_doc},
#endif

--
Repository URL: http://hg.python.org/cpython
cpython (merge default -> default): merge [ In reply to ]
http://hg.python.org/cpython/rev/fbbb14604e94
changeset: 76139:fbbb14604e94
parent: 76138:1a3eb3b8ba42
parent: 76137:d8c5c0f7aa56
user: Brett Cannon <brett@python.org>
date: Fri Apr 06 12:54:57 2012 -0400
summary:
merge

files:
.bzrignore | 1 -
.gitignore | 1 -
.hgignore | 1 -
Doc/library/_thread.rst | 2 +-
Doc/library/collections.rst | 4 +-
Doc/library/subprocess.rst | 2 +-
Doc/library/threading.rst | 4 +-
Doc/whatsnew/3.3.rst | 51 +-
Include/methodobject.h | 16 +-
Include/object.h | 5 +
Lib/collections/abc.py | 10 +-
Lib/idlelib/NEWS.txt | 3 +
Lib/idlelib/ScriptBinding.py | 12 +-
Lib/idlelib/tabbedpages.py | 4 +-
Lib/multiprocessing/connection.py | 4 +
Lib/test/seq_tests.py | 7 +
Lib/test/test_array.py | 14 +
Lib/test/test_asyncore.py | 7 +-
Lib/test/test_builtin.py | 41 +
Lib/test/test_bytes.py | 18 +
Lib/test/test_decimal.py | 72 +
Lib/test/test_deque.py | 13 +
Lib/test/test_dict.py | 54 +
Lib/test/test_enumerate.py | 30 +-
Lib/test/test_iter.py | 43 +-
Lib/test/test_itertools.py | 386 ++++++-
Lib/test/test_list.py | 28 +
Lib/test/test_multiprocessing.py | 4 +
Lib/test/test_range.py | 24 +-
Lib/test/test_set.py | 21 +
Lib/test/test_tools.py | 73 +-
Lib/test/test_tuple.py | 29 +
Lib/test/test_xml_etree.py | 35 +
Lib/tkinter/font.py | 63 +-
Lib/tkinter/ttk.py | 2 +-
Lib/webbrowser.py | 8 +
Makefile.pre.in | 2 +-
Misc/ACKS | 2 +
Misc/NEWS | 20 +-
Modules/_collectionsmodule.c | 93 +-
Modules/_decimal/_decimal.c | 16 +-
Modules/_decimal/tests/deccheck.py | 1 +
Modules/_elementtree.c | 88 +-
Modules/arraymodule.c | 30 +-
Modules/itertoolsmodule.c | 890 ++++++++++++++-
Objects/bytearrayobject.c | 36 +-
Objects/bytesobject.c | 34 +
Objects/dictobject.c | 53 +
Objects/enumobject.c | 50 +-
Objects/iterobject.c | 47 +-
Objects/listobject.c | 80 +
Objects/object.c | 13 +
Objects/rangeobject.c | 92 +
Objects/setobject.c | 45 +-
Objects/tupleobject.c | 31 +
Objects/unicodeobject.c | 85 +-
Python/bltinmodule.c | 56 +-
Python/pythonrun.c | 57 +-
Tools/scripts/abitype.py | 88 +-
Tools/scripts/find_recursionlimit.py | 24 +-
Tools/scripts/findnocoding.py | 46 +-
Tools/scripts/fixcid.py | 2 +-
Tools/scripts/md5sum.py | 2 +-
Tools/scripts/parseentities.py | 3 +-
Tools/scripts/pdeps.py | 10 +-
65 files changed, 2751 insertions(+), 337 deletions(-)


diff --git a/.bzrignore b/.bzrignore
--- a/.bzrignore
+++ b/.bzrignore
@@ -33,7 +33,6 @@
Modules/config.c
Modules/ld_so_aix
Parser/pgen
-Parser/pgen.stamp
Lib/test/data/*
Lib/lib2to3/Grammar*.pickle
Lib/lib2to3/PatternGrammar*.pickle
diff --git a/.gitignore b/.gitignore
--- a/.gitignore
+++ b/.gitignore
@@ -32,7 +32,6 @@
PCbuild/*.pdb
PCbuild/Win32-temp-*
Parser/pgen
-Parser/pgen.stamp
__pycache__
autom4te.cache
build/
diff --git a/.hgignore b/.hgignore
--- a/.hgignore
+++ b/.hgignore
@@ -32,7 +32,6 @@
Modules/config.c
Modules/ld_so_aix$
Parser/pgen$
-Parser/pgen.stamp$
PCbuild/amd64/
^core
^python-gdb.py
diff --git a/Doc/library/_thread.rst b/Doc/library/_thread.rst
--- a/Doc/library/_thread.rst
+++ b/Doc/library/_thread.rst
@@ -94,7 +94,7 @@
*size* argument specifies the stack size to be used for subsequently created
threads, and must be 0 (use platform or configured default) or a positive
integer value of at least 32,768 (32kB). If changing the thread stack size is
- unsupported, a :exc:`ThreadError` is raised. If the specified stack size is
+ unsupported, a :exc:`RuntimeError` is raised. If the specified stack size is
invalid, a :exc:`ValueError` is raised and the stack size is unmodified. 32kB
is currently the minimum supported stack size value to guarantee sufficient
stack space for the interpreter itself. Note that some platforms may have
diff --git a/Doc/library/collections.rst b/Doc/library/collections.rst
--- a/Doc/library/collections.rst
+++ b/Doc/library/collections.rst
@@ -41,6 +41,8 @@
:class:`ChainMap` objects
-------------------------

+.. versionadded:: 3.3
+
A :class:`ChainMap` class is provided for quickly linking a number of mappings
so they can be treated as a single unit. It is often much faster than creating
a new dictionary and running multiple :meth:`~dict.update` calls.
@@ -91,8 +93,6 @@
The use-cases also parallel those for the builtin :func:`super` function.
A reference to ``d.parents`` is equivalent to: ``ChainMap(*d.maps[1:])``.

- .. versionadded:: 3.3
-
Example of simulating Python's internal lookup chain::

import builtins
diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst
--- a/Doc/library/subprocess.rst
+++ b/Doc/library/subprocess.rst
@@ -804,7 +804,7 @@
to receive a SIGPIPE if p2 exits before p1.

Alternatively, for trusted input, the shell's own pipeline support may still
-be used directly:
+be used directly::

output=`dmesg | grep hda`
# becomes
diff --git a/Doc/library/threading.rst b/Doc/library/threading.rst
--- a/Doc/library/threading.rst
+++ b/Doc/library/threading.rst
@@ -174,7 +174,7 @@
*size* argument specifies the stack size to be used for subsequently created
threads, and must be 0 (use platform or configured default) or a positive
integer value of at least 32,768 (32kB). If changing the thread stack size is
- unsupported, a :exc:`ThreadError` is raised. If the specified stack size is
+ unsupported, a :exc:`RuntimeError` is raised. If the specified stack size is
invalid, a :exc:`ValueError` is raised and the stack size is unmodified. 32kB
is currently the minimum supported stack size value to guarantee sufficient
stack space for the interpreter itself. Note that some platforms may have
@@ -452,7 +452,7 @@
are blocked waiting for the lock to become unlocked, allow exactly one of them
to proceed.

- Do not call this method when the lock is unlocked.
+ When invoked on an unlocked lock, a :exc:`RuntimeError` is raised.

There is no return value.

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
@@ -486,6 +486,8 @@

(:issue:`10516`)

+.. XXX mention new error messages for passing wrong number of arguments to functions
+
New and Improved Modules
========================

@@ -572,6 +574,26 @@

The ``unicode_internal`` codec has been deprecated.

+
+collections
+-----------
+
+Addition of a new :class:`~collections.ChainMap` class to allow treating a
+number of mappings as a single unit.
+
+(Written by Raymond Hettinger for :issue:`11089`, made public in
+:issue:`11297`)
+
+The abstract base classes have been moved in a new :mod:`collections.abc`
+module, to better differentiate between the abstract and the concrete
+collections classes. Aliases for ABCs are still present in the
+:mod:`collections` module to preserve existing imports.
+
+(:issue:`11085`)
+
+.. XXX addition of __slots__ to ABCs not recorded here: internal detail
+
+
crypt
-----

@@ -865,11 +887,12 @@
---------

:mod:`distutils` has undergone additions and refactoring under a new name,
-:mod:`packaging`, to allow developers to break backward compatibility.
+:mod:`packaging`, to allow developers to make far-reaching changes without
+being constrained by backward compatibility.
:mod:`distutils` is still provided in the standard library, but users are
encouraged to transition to :mod:`packaging`. For older versions of Python, a
-backport compatible with 2.4+ and 3.1+ will be made available on PyPI under the
-name :mod:`distutils2`.
+backport compatible with Python 2.5 and newer and 3.2 is available on PyPI
+under the name `distutils2 <http://pypi.python.org/pypi/Distutils2>`_.

.. TODO add examples and howto to the packaging docs and link to them

@@ -1057,12 +1080,24 @@
(:issue:`1673007`)


+webbrowser
+----------
+
+The :mod:`webbrowser` module supports more browsers: Google Chrome (named
+:program:`chrome`, :program:`chromium`, :program:`chrome-browser` or
+:program:`chromium-browser` depending on the version and operating system) as
+well as the the generic launchers :program:`xdg-open` from the FreeDesktop.org
+project and :program:`gvfs-open` which is the default URI handler for GNOME 3.
+
+(:issue:`13620` and :issue:`14493`)
+
+
Optimizations
=============

Major performance enhancements have been added:

-* Thanks to the :pep:`393`, some operations on Unicode strings has been optimized:
+* Thanks to :pep:`393`, some operations on Unicode strings have been optimized:

* the memory footprint is divided by 2 to 4 depending on the text
* encode an ASCII string to UTF-8 doesn't need to encode characters anymore,
@@ -1081,7 +1116,7 @@

* :c:func:`PyMemoryView_FromMemory`

-* The :pep:`393` added new Unicode types, macros and functions:
+* :pep:`393` added new Unicode types, macros and functions:

* High-level API:

@@ -1124,7 +1159,7 @@
Deprecated Python modules, functions and methods
------------------------------------------------

-* The :mod:`distutils` modules has been deprecated. Use the new
+* The :mod:`distutils` module has been deprecated. Use the new
:mod:`packaging` module instead.
* The ``unicode_internal`` codec has been deprecated because of the
:pep:`393`, use UTF-8, UTF-16 (``utf-16-le`` or ``utf-16-be``), or UTF-32
@@ -1143,7 +1178,7 @@
Deprecated functions and types of the C API
-------------------------------------------

-The :c:type:`Py_UNICODE` has been deprecated by the :pep:`393` and will be
+The :c:type:`Py_UNICODE` has been deprecated by :pep:`393` and will be
removed in Python 4. All functions using this type are deprecated:

Unicode functions and methods using :c:type:`Py_UNICODE` and
@@ -1245,7 +1280,7 @@
functions using this type are deprecated (but will stay available for
at least five years). If you were using low-level Unicode APIs to
construct and access unicode objects and you want to benefit of the
- memory footprint reduction provided by the PEP 393, you have to convert
+ memory footprint reduction provided by PEP 393, you have to convert
your code to the new :doc:`Unicode API <../c-api/unicode>`.

However, if you only have been using high-level functions such as
diff --git a/Include/methodobject.h b/Include/methodobject.h
--- a/Include/methodobject.h
+++ b/Include/methodobject.h
@@ -17,7 +17,7 @@

typedef PyObject *(*PyCFunction)(PyObject *, PyObject *);
typedef PyObject *(*PyCFunctionWithKeywords)(PyObject *, PyObject *,
- PyObject *);
+ PyObject *);
typedef PyObject *(*PyNoArgsFunction)(PyObject *);

PyAPI_FUNC(PyCFunction) PyCFunction_GetFunction(PyObject *);
@@ -33,22 +33,22 @@
(((PyCFunctionObject *)func) -> m_ml -> ml_flags & METH_STATIC ? \
NULL : ((PyCFunctionObject *)func) -> m_self)
#define PyCFunction_GET_FLAGS(func) \
- (((PyCFunctionObject *)func) -> m_ml -> ml_flags)
+ (((PyCFunctionObject *)func) -> m_ml -> ml_flags)
#endif
PyAPI_FUNC(PyObject *) PyCFunction_Call(PyObject *, PyObject *, PyObject *);

struct PyMethodDef {
- const char *ml_name; /* The name of the built-in function/method */
- PyCFunction ml_meth; /* The C function that implements it */
- int ml_flags; /* Combination of METH_xxx flags, which mostly
- describe the args expected by the C func */
- const char *ml_doc; /* The __doc__ attribute, or NULL */
+ const char *ml_name; /* The name of the built-in function/method */
+ PyCFunction ml_meth; /* The C function that implements it */
+ int ml_flags; /* Combination of METH_xxx flags, which mostly
+ describe the args expected by the C func */
+ const char *ml_doc; /* The __doc__ attribute, or NULL */
};
typedef struct PyMethodDef PyMethodDef;

#define PyCFunction_New(ML, SELF) PyCFunction_NewEx((ML), (SELF), NULL)
PyAPI_FUNC(PyObject *) PyCFunction_NewEx(PyMethodDef *, PyObject *,
- PyObject *);
+ PyObject *);

/* Flag passed to newmethodobject */
/* #define METH_OLDARGS 0x0000 -- unsupported now */
diff --git a/Include/object.h b/Include/object.h
--- a/Include/object.h
+++ b/Include/object.h
@@ -535,6 +535,11 @@
_PyObject_GenericSetAttrWithDict(PyObject *, PyObject *,
PyObject *, PyObject *);

+/* Helper to look up a builtin object */
+#ifndef Py_LIMITED_API
+PyAPI_FUNC(PyObject *)
+_PyObject_GetBuiltin(const char *name);
+#endif

/* PyObject_Dir(obj) acts like Python builtins.dir(obj), returning a
list of strings. PyObject_Dir(NULL) is like builtins.dir(),
diff --git a/Lib/collections/abc.py b/Lib/collections/abc.py
--- a/Lib/collections/abc.py
+++ b/Lib/collections/abc.py
@@ -18,9 +18,13 @@
"ByteString",
]

-
-### collection related types which are not exposed through builtin ###
-## iterators ##
+# Private list of types that we want to register with the various ABCs
+# so that they will pass tests like:
+# it = iter(somebytearray)
+# assert isinstance(it, Iterable)
+# Note: in other implementations, these types many not be distinct
+# and they make have their own implementation specific types that
+# are not included on this list.
bytes_iterator = type(iter(b''))
bytearray_iterator = type(iter(bytearray()))
#callable_iterator = ???
diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt
--- a/Lib/idlelib/NEWS.txt
+++ b/Lib/idlelib/NEWS.txt
@@ -1,6 +1,9 @@
What's New in IDLE 3.3?
=========================

+- Issue #8515: Set __file__ when run file in IDLE.
+ Initial patch by Bruce Frederiksen.
+
- IDLE can be launched as `python -m idlelib`

- Issue #14409: IDLE now properly executes commands in the Shell window
diff --git a/Lib/idlelib/ScriptBinding.py b/Lib/idlelib/ScriptBinding.py
--- a/Lib/idlelib/ScriptBinding.py
+++ b/Lib/idlelib/ScriptBinding.py
@@ -150,16 +150,16 @@
dirname = os.path.dirname(filename)
# XXX Too often this discards arguments the user just set...
interp.runcommand("""if 1:
- _filename = %r
+ __file__ = {filename!r}
import sys as _sys
from os.path import basename as _basename
if (not _sys.argv or
- _basename(_sys.argv[0]) != _basename(_filename)):
- _sys.argv = [_filename]
+ _basename(_sys.argv[0]) != _basename(__file__)):
+ _sys.argv = [__file__]
import os as _os
- _os.chdir(%r)
- del _filename, _sys, _basename, _os
- \n""" % (filename, dirname))
+ _os.chdir({dirname!r})
+ del _sys, _basename, _os
+ \n""".format(filename=filename, dirname=dirname))
interp.prepend_syspath(filename)
# XXX KBK 03Jul04 When run w/o subprocess, runtime warnings still
# go to __stderr__. With subprocess, they go to the shell.
diff --git a/Lib/idlelib/tabbedpages.py b/Lib/idlelib/tabbedpages.py
--- a/Lib/idlelib/tabbedpages.py
+++ b/Lib/idlelib/tabbedpages.py
@@ -78,7 +78,7 @@
def remove_tab(self, tab_name):
"""Remove the tab named <tab_name>"""
if not tab_name in self._tab_names:
- raise KeyError("No such Tab: '%s" % page_name)
+ raise KeyError("No such Tab: '%s" % tab_name)

self._tab_names.remove(tab_name)
self._arrange_tabs()
@@ -88,7 +88,7 @@
if tab_name == self._selected_tab:
return
if tab_name is not None and tab_name not in self._tabs:
- raise KeyError("No such Tab: '%s" % page_name)
+ raise KeyError("No such Tab: '%s" % tab_name)

# deselect the current selected tab
if self._selected_tab is not None:
diff --git a/Lib/multiprocessing/connection.py b/Lib/multiprocessing/connection.py
--- a/Lib/multiprocessing/connection.py
+++ b/Lib/multiprocessing/connection.py
@@ -111,6 +111,10 @@
if sys.platform != 'win32' and family == 'AF_PIPE':
raise ValueError('Family %s is not recognized.' % family)

+ if sys.platform == 'win32' and family == 'AF_UNIX':
+ # double check
+ if not hasattr(socket, family):
+ raise ValueError('Family %s is not recognized.' % family)

def address_type(address):
'''
diff --git a/Lib/test/seq_tests.py b/Lib/test/seq_tests.py
--- a/Lib/test/seq_tests.py
+++ b/Lib/test/seq_tests.py
@@ -4,6 +4,7 @@

import unittest
import sys
+import pickle

# Various iterables
# This is used for checking the constructor (here and in test_deque.py)
@@ -388,3 +389,9 @@
self.assertEqual(a.index(0, -4*sys.maxsize, 4*sys.maxsize), 2)
self.assertRaises(ValueError, a.index, 0, 4*sys.maxsize,-4*sys.maxsize)
self.assertRaises(ValueError, a.index, 2, 0, -10)
+
+ def test_pickle(self):
+ lst = self.type2test([4, 5, 6, 7])
+ lst2 = pickle.loads(pickle.dumps(lst))
+ self.assertEqual(lst2, lst)
+ self.assertNotEqual(id(lst2), id(lst))
diff --git a/Lib/test/test_array.py b/Lib/test/test_array.py
--- a/Lib/test/test_array.py
+++ b/Lib/test/test_array.py
@@ -285,6 +285,20 @@
self.assertEqual(a.x, b.x)
self.assertEqual(type(a), type(b))

+ def test_iterator_pickle(self):
+ data = array.array(self.typecode, self.example)
+ orgit = iter(data)
+ d = pickle.dumps(orgit)
+ it = pickle.loads(d)
+ self.assertEqual(type(orgit), type(it))
+ self.assertEqual(list(it), list(data))
+
+ if len(data):
+ it = pickle.loads(d)
+ next(it)
+ d = pickle.dumps(it)
+ self.assertEqual(list(it), list(data)[1:])
+
def test_insert(self):
a = array.array(self.typecode, self.example)
a.insert(0, self.example[0])
diff --git a/Lib/test/test_asyncore.py b/Lib/test/test_asyncore.py
--- a/Lib/test/test_asyncore.py
+++ b/Lib/test/test_asyncore.py
@@ -74,15 +74,16 @@
pass
else:
n = 200
- while n > 0:
- r, w, e = select.select([conn], [], [])
+ start = time.time()
+ while n > 0 and time.time() - start < 3.0:
+ r, w, e = select.select([conn], [], [], 0.1)
if r:
+ n -= 1
data = conn.recv(10)
# keep everything except for the newline terminator
buf.write(data.replace(b'\n', b''))
if b'\n' in data:
break
- n -= 1
time.sleep(0.01)

conn.close()
diff --git a/Lib/test/test_builtin.py b/Lib/test/test_builtin.py
--- a/Lib/test/test_builtin.py
+++ b/Lib/test/test_builtin.py
@@ -14,6 +14,7 @@
import traceback
from test.support import TESTFN, unlink, run_unittest, check_warnings
from operator import neg
+import pickle
try:
import pty, signal
except ImportError:
@@ -110,7 +111,30 @@
def __iter__(self):
raise RuntimeError

+def filter_char(arg):
+ return ord(arg) > ord("d")
+
+def map_char(arg):
+ return chr(ord(arg)+1)
+
class BuiltinTest(unittest.TestCase):
+ # Helper to check picklability
+ def check_iter_pickle(self, it, seq):
+ itorg = it
+ d = pickle.dumps(it)
+ it = pickle.loads(d)
+ self.assertEqual(type(itorg), type(it))
+ self.assertEqual(list(it), seq)
+
+ #test the iterator after dropping one from it
+ it = pickle.loads(d)
+ try:
+ next(it)
+ except StopIteration:
+ return
+ d = pickle.dumps(it)
+ it = pickle.loads(d)
+ self.assertEqual(list(it), seq[1:])

def test_import(self):
__import__('sys')
@@ -566,6 +590,11 @@
self.assertEqual(list(filter(lambda x: x>=3, (1, 2, 3, 4))), [3, 4])
self.assertRaises(TypeError, list, filter(42, (1, 2)))

+ def test_filter_pickle(self):
+ f1 = filter(filter_char, "abcdeabcde")
+ f2 = filter(filter_char, "abcdeabcde")
+ self.check_iter_pickle(f1, list(f2))
+
def test_getattr(self):
self.assertTrue(getattr(sys, 'stdout') is sys.stdout)
self.assertRaises(TypeError, getattr, sys, 1)
@@ -759,6 +788,11 @@
raise RuntimeError
self.assertRaises(RuntimeError, list, map(badfunc, range(5)))

+ def test_map_pickle(self):
+ m1 = map(map_char, "Is this the real life?")
+ m2 = map(map_char, "Is this the real life?")
+ self.check_iter_pickle(m1, list(m2))
+
def test_max(self):
self.assertEqual(max('123123'), '3')
self.assertEqual(max(1, 2, 3), 3)
@@ -1300,6 +1334,13 @@
return i
self.assertRaises(ValueError, list, zip(BadSeq(), BadSeq()))

+ def test_zip_pickle(self):
+ a = (1, 2, 3)
+ b = (4, 5, 6)
+ t = [(1, 4), (2, 5), (3, 6)]
+ z1 = zip(a, b)
+ self.check_iter_pickle(z1, t)
+
def test_format(self):
# Test the basic machinery of the format() builtin. Don't test
# the specifics of the various formatters
diff --git a/Lib/test/test_bytes.py b/Lib/test/test_bytes.py
--- a/Lib/test/test_bytes.py
+++ b/Lib/test/test_bytes.py
@@ -518,6 +518,24 @@
q = pickle.loads(ps)
self.assertEqual(b, q)

+ def test_iterator_pickling(self):
+ for b in b"", b"a", b"abc", b"\xffab\x80", b"\0\0\377\0\0":
+ it = itorg = iter(self.type2test(b))
+ data = list(self.type2test(b))
+ d = pickle.dumps(it)
+ it = pickle.loads(d)
+ self.assertEqual(type(itorg), type(it))
+ self.assertEqual(list(it), data)
+
+ it = pickle.loads(d)
+ try:
+ next(it)
+ except StopIteration:
+ continue
+ d = pickle.dumps(it)
+ it = pickle.loads(d)
+ self.assertEqual(list(it), data[1:])
+
def test_strip(self):
b = self.type2test(b'mississippi')
self.assertEqual(b.strip(b'i'), b'mississipp')
diff --git a/Lib/test/test_decimal.py b/Lib/test/test_decimal.py
--- a/Lib/test/test_decimal.py
+++ b/Lib/test/test_decimal.py
@@ -4953,6 +4953,78 @@
self.assertRaises(ValueError, get_fmt, 12345, invalid_dot, 'g')
self.assertRaises(ValueError, get_fmt, 12345, invalid_sep, 'g')

+ def test_exact_conversion(self):
+ Decimal = C.Decimal
+ localcontext = C.localcontext
+ InvalidOperation = C.InvalidOperation
+
+ with localcontext() as c:
+
+ c.traps[InvalidOperation] = True
+
+ # Clamped
+ x = "0e%d" % sys.maxsize
+ self.assertRaises(InvalidOperation, Decimal, x)
+
+ x = "0e%d" % (-sys.maxsize-1)
+ self.assertRaises(InvalidOperation, Decimal, x)
+
+ # Overflow
+ x = "1e%d" % sys.maxsize
+ self.assertRaises(InvalidOperation, Decimal, x)
+
+ # Underflow
+ x = "1e%d" % (-sys.maxsize-1)
+ self.assertRaises(InvalidOperation, Decimal, x)
+
+ def test_from_tuple(self):
+ Decimal = C.Decimal
+ localcontext = C.localcontext
+ InvalidOperation = C.InvalidOperation
+ Overflow = C.Overflow
+ Underflow = C.Underflow
+
+ with localcontext() as c:
+
+ c.traps[InvalidOperation] = True
+ c.traps[Overflow] = True
+ c.traps[Underflow] = True
+
+ # SSIZE_MAX
+ x = (1, (), sys.maxsize)
+ self.assertEqual(str(c.create_decimal(x)), '-0E+999999')
+ self.assertRaises(InvalidOperation, Decimal, x)
+
+ x = (1, (0, 1, 2), sys.maxsize)
+ self.assertRaises(Overflow, c.create_decimal, x)
+ self.assertRaises(InvalidOperation, Decimal, x)
+
+ # SSIZE_MIN
+ x = (1, (), -sys.maxsize-1)
+ self.assertEqual(str(c.create_decimal(x)), '-0E-1000026')
+ self.assertRaises(InvalidOperation, Decimal, x)
+
+ x = (1, (0, 1, 2), -sys.maxsize-1)
+ self.assertRaises(Underflow, c.create_decimal, x)
+ self.assertRaises(InvalidOperation, Decimal, x)
+
+ # OverflowError
+ x = (1, (), sys.maxsize+1)
+ self.assertRaises(OverflowError, c.create_decimal, x)
+ self.assertRaises(OverflowError, Decimal, x)
+
+ x = (1, (), -sys.maxsize-2)
+ self.assertRaises(OverflowError, c.create_decimal, x)
+ self.assertRaises(OverflowError, Decimal, x)
+
+ # Specials
+ x = (1, (), "N")
+ self.assertEqual(str(Decimal(x)), '-sNaN')
+ x = (1, (0,), "N")
+ self.assertEqual(str(Decimal(x)), '-sNaN')
+ x = (1, (0, 1), "N")
+ self.assertEqual(str(Decimal(x)), '-sNaN1')
+

all_tests = [.
CExplicitConstructionTest, PyExplicitConstructionTest,
diff --git a/Lib/test/test_deque.py b/Lib/test/test_deque.py
--- a/Lib/test/test_deque.py
+++ b/Lib/test/test_deque.py
@@ -471,6 +471,19 @@
## self.assertNotEqual(id(d), id(e))
## self.assertEqual(id(e), id(e[-1]))

+ def test_iterator_pickle(self):
+ data = deque(range(200))
+ it = itorg = iter(data)
+ d = pickle.dumps(it)
+ it = pickle.loads(d)
+ self.assertEqual(type(itorg), type(it))
+ self.assertEqual(list(it), list(data))
+
+ it = pickle.loads(d)
+ next(it)
+ d = pickle.dumps(it)
+ self.assertEqual(list(it), list(data)[1:])
+
def test_deepcopy(self):
mut = [10]
d = deque([mut])
diff --git a/Lib/test/test_dict.py b/Lib/test/test_dict.py
--- a/Lib/test/test_dict.py
+++ b/Lib/test/test_dict.py
@@ -2,7 +2,9 @@
from test import support

import collections, random, string
+import collections.abc
import gc, weakref
+import pickle


class DictTest(unittest.TestCase):
@@ -803,6 +805,58 @@
pass
self._tracked(MyDict())

+ def test_iterator_pickling(self):
+ data = {1:"a", 2:"b", 3:"c"}
+ it = iter(data)
+ d = pickle.dumps(it)
+ it = pickle.loads(d)
+ self.assertEqual(sorted(it), sorted(data))
+
+ it = pickle.loads(d)
+ try:
+ drop = next(it)
+ except StopIteration:
+ return
+ d = pickle.dumps(it)
+ it = pickle.loads(d)
+ del data[drop]
+ self.assertEqual(sorted(it), sorted(data))
+
+ def test_itemiterator_pickling(self):
+ data = {1:"a", 2:"b", 3:"c"}
+ # dictviews aren't picklable, only their iterators
+ itorg = iter(data.items())
+ d = pickle.dumps(itorg)
+ it = pickle.loads(d)
+ # note that the type of type of the unpickled iterator
+ # is not necessarily the same as the original. It is
+ # merely an object supporting the iterator protocol, yielding
+ # the same objects as the original one.
+ # self.assertEqual(type(itorg), type(it))
+ self.assertTrue(isinstance(it, collections.abc.Iterator))
+ self.assertEqual(dict(it), data)
+
+ it = pickle.loads(d)
+ drop = next(it)
+ d = pickle.dumps(it)
+ it = pickle.loads(d)
+ del data[drop[0]]
+ self.assertEqual(dict(it), data)
+
+ def test_valuesiterator_pickling(self):
+ data = {1:"a", 2:"b", 3:"c"}
+ # data.values() isn't picklable, only its iterator
+ it = iter(data.values())
+ d = pickle.dumps(it)
+ it = pickle.loads(d)
+ self.assertEqual(sorted(list(it)), sorted(list(data.values())))
+
+ it = pickle.loads(d)
+ drop = next(it)
+ d = pickle.dumps(it)
+ it = pickle.loads(d)
+ values = list(it) + [drop]
+ self.assertEqual(sorted(values), sorted(list(data.values())))

from test import mapping_tests

diff --git a/Lib/test/test_enumerate.py b/Lib/test/test_enumerate.py
--- a/Lib/test/test_enumerate.py
+++ b/Lib/test/test_enumerate.py
@@ -1,5 +1,6 @@
import unittest
import sys
+import pickle

from test import support

@@ -61,7 +62,25 @@
def __iter__(self):
return self

-class EnumerateTestCase(unittest.TestCase):
+class PickleTest:
+ # Helper to check picklability
+ def check_pickle(self, itorg, seq):
+ d = pickle.dumps(itorg)
+ it = pickle.loads(d)
+ self.assertEqual(type(itorg), type(it))
+ self.assertEqual(list(it), seq)
+
+ it = pickle.loads(d)
+ try:
+ next(it)
+ except StopIteration:
+ self.assertFalse(seq[1:])
+ return
+ d = pickle.dumps(it)
+ it = pickle.loads(d)
+ self.assertEqual(list(it), seq[1:])
+
+class EnumerateTestCase(unittest.TestCase, PickleTest):

enum = enumerate
seq, res = 'abc', [(0,'a'), (1,'b'), (2,'c')]
@@ -73,6 +92,9 @@
self.assertEqual(list(self.enum(self.seq)), self.res)
self.enum.__doc__

+ def test_pickle(self):
+ self.check_pickle(self.enum(self.seq), self.res)
+
def test_getitemseqn(self):
self.assertEqual(list(self.enum(G(self.seq))), self.res)
e = self.enum(G(''))
@@ -126,7 +148,7 @@
seq = range(10,20000,2)
res = list(zip(range(20000), seq))

-class TestReversed(unittest.TestCase):
+class TestReversed(unittest.TestCase, PickleTest):

def test_simple(self):
class A:
@@ -212,6 +234,10 @@
ngi = NoGetItem()
self.assertRaises(TypeError, reversed, ngi)

+ def test_pickle(self):
+ for data in 'abc', range(5), tuple(enumerate('abc')), range(1,17,5):
+ self.check_pickle(reversed(data), list(data)[::-1])
+

class EnumerateStartTestCase(EnumerateTestCase):

diff --git a/Lib/test/test_iter.py b/Lib/test/test_iter.py
--- a/Lib/test/test_iter.py
+++ b/Lib/test/test_iter.py
@@ -2,6 +2,8 @@

import unittest
from test.support import run_unittest, TESTFN, unlink, cpython_only
+import pickle
+import collections.abc

# Test result of triple loop (too big to inline)
TRIPLETS = [.(0, 0, 0), (0, 0, 1), (0, 0, 2),
@@ -28,6 +30,8 @@
raise StopIteration
self.i = res + 1
return res
+ def __iter__(self):
+ return self

class IteratingSequenceClass:
def __init__(self, n):
@@ -49,7 +53,9 @@
class TestCase(unittest.TestCase):

# Helper to check that an iterator returns a given sequence
- def check_iterator(self, it, seq):
+ def check_iterator(self, it, seq, pickle=True):
+ if pickle:
+ self.check_pickle(it, seq)
res = []
while 1:
try:
@@ -60,12 +66,33 @@
self.assertEqual(res, seq)

# Helper to check that a for loop generates a given sequence
- def check_for_loop(self, expr, seq):
+ def check_for_loop(self, expr, seq, pickle=True):
+ if pickle:
+ self.check_pickle(iter(expr), seq)
res = []
for val in expr:
res.append(val)
self.assertEqual(res, seq)

+ # Helper to check picklability
+ def check_pickle(self, itorg, seq):
+ d = pickle.dumps(itorg)
+ it = pickle.loads(d)
+ # Cannot assert type equality because dict iterators unpickle as list
+ # iterators.
+ # self.assertEqual(type(itorg), type(it))
+ self.assertTrue(isinstance(it, collections.abc.Iterator))
+ self.assertEqual(list(it), seq)
+
+ it = pickle.loads(d)
+ try:
+ next(it)
+ except StopIteration:
+ return
+ d = pickle.dumps(it)
+ it = pickle.loads(d)
+ self.assertEqual(list(it), seq[1:])
+
# Test basic use of iter() function
def test_iter_basic(self):
self.check_iterator(iter(range(10)), list(range(10)))
@@ -138,7 +165,7 @@
if i > 100:
raise IndexError # Emergency stop
return i
- self.check_iterator(iter(C(), 10), list(range(10)))
+ self.check_iterator(iter(C(), 10), list(range(10)), pickle=False)

# Test two-argument iter() with function
def test_iter_function(self):
@@ -146,7 +173,7 @@
i = state[0]
state[0] = i+1
return i
- self.check_iterator(iter(spam, 10), list(range(10)))
+ self.check_iterator(iter(spam, 10), list(range(10)), pickle=False)

# Test two-argument iter() with function that raises StopIteration
def test_iter_function_stop(self):
@@ -156,7 +183,7 @@
raise StopIteration
state[0] = i+1
return i
- self.check_iterator(iter(spam, 20), list(range(10)))
+ self.check_iterator(iter(spam, 20), list(range(10)), pickle=False)

# Test exception propagation through function iterator
def test_exception_function(self):
@@ -198,7 +225,7 @@
if i == 10:
raise StopIteration
return SequenceClass.__getitem__(self, i)
- self.check_for_loop(MySequenceClass(20), list(range(10)))
+ self.check_for_loop(MySequenceClass(20), list(range(10)), pickle=False)

# Test a big range
def test_iter_big_range(self):
@@ -237,8 +264,8 @@
f.close()
f = open(TESTFN, "r")
try:
- self.check_for_loop(f, ["0\n", "1\n", "2\n", "3\n", "4\n"])
- self.check_for_loop(f, [])
+ self.check_for_loop(f, ["0\n", "1\n", "2\n", "3\n", "4\n"], pickle=False)
+ self.check_for_loop(f, [], pickle=False)
finally:
f.close()
try:
diff --git a/Lib/test/test_itertools.py b/Lib/test/test_itertools.py
--- a/Lib/test/test_itertools.py
+++ b/Lib/test/test_itertools.py
@@ -37,6 +37,13 @@
'Test predicate'
return x%2==1

+def tupleize(*args):
+ return args
+
+def irange(n):
+ for i in range(n):
+ yield i
+
class StopNow:
'Class emulating an empty iterable.'
def __iter__(self):
@@ -55,8 +62,59 @@
'Factorial'
return prod(range(1, n+1))

+# root level methods for pickling ability
+def testR(r):
+ return r[0]
+
+def testR2(r):
+ return r[2]
+
+def underten(x):
+ return x<10
+
class TestBasicOps(unittest.TestCase):

+ def pickletest(self, it, stop=4, take=1, compare=None):
+ """Test that an iterator is the same after pickling, also when part-consumed"""
+ def expand(it, i=0):
+ # Recursively expand iterables, within sensible bounds
+ if i > 10:
+ raise RuntimeError("infinite recursion encountered")
+ if isinstance(it, str):
+ return it
+ try:
+ l = list(islice(it, stop))
+ except TypeError:
+ return it # can't expand it
+ return [expand(e, i+1) for e in l]
+
+ # Test the initial copy against the original
+ dump = pickle.dumps(it)
+ i2 = pickle.loads(dump)
+ self.assertEqual(type(it), type(i2))
+ a, b = expand(it), expand(i2)
+ self.assertEqual(a, b)
+ if compare:
+ c = expand(compare)
+ self.assertEqual(a, c)
+
+ # Take from the copy, and create another copy and compare them.
+ i3 = pickle.loads(dump)
+ took = 0
+ try:
+ for i in range(take):
+ next(i3)
+ took += 1
+ except StopIteration:
+ pass #in case there is less data than 'take'
+ dump = pickle.dumps(i3)
+ i4 = pickle.loads(dump)
+ a, b = expand(i3), expand(i4)
+ self.assertEqual(a, b)
+ if compare:
+ c = expand(compare[took:])
+ self.assertEqual(a, c);
+
def test_accumulate(self):
self.assertEqual(list(accumulate(range(10))), # one positional arg
[0, 1, 3, 6, 10, 15, 21, 28, 36, 45])
@@ -83,6 +141,7 @@
[2, 16, 144, 720, 5040, 0, 0, 0, 0, 0])
with self.assertRaises(TypeError):
list(accumulate(s, chr)) # unary-operation
+ self.pickletest(accumulate(range(10))) # test pickling

def test_chain(self):

@@ -106,14 +165,43 @@
self.assertEqual(take(4, chain.from_iterable(['abc', 'def'])), list('abcd'))
self.assertRaises(TypeError, list, chain.from_iterable([2, 3]))

+ def test_chain_reducible(self):
+ operators = [copy.deepcopy,
+ lambda s: pickle.loads(pickle.dumps(s))]
+ for oper in operators:
+ it = chain('abc', 'def')
+ self.assertEqual(list(oper(it)), list('abcdef'))
+ self.assertEqual(next(it), 'a')
+ self.assertEqual(list(oper(it)), list('bcdef'))
+
+ self.assertEqual(list(oper(chain(''))), [])
+ self.assertEqual(take(4, oper(chain('abc', 'def'))), list('abcd'))
+ self.assertRaises(TypeError, list, oper(chain(2, 3)))
+ self.pickletest(chain('abc', 'def'), compare=list('abcdef'))
+
def test_combinations(self):
self.assertRaises(TypeError, combinations, 'abc') # missing r argument
self.assertRaises(TypeError, combinations, 'abc', 2, 1) # too many arguments
self.assertRaises(TypeError, combinations, None) # pool is not iterable
self.assertRaises(ValueError, combinations, 'abc', -2) # r is negative
- self.assertEqual(list(combinations('abc', 32)), []) # r > n
- self.assertEqual(list(combinations(range(4), 3)),
- [(0,1,2), (0,1,3), (0,2,3), (1,2,3)])
+
+ for op in (lambda a:a, lambda a:pickle.loads(pickle.dumps(a))):
+ self.assertEqual(list(op(combinations('abc', 32))), []) # r > n
+
+ self.assertEqual(list(op(combinations('ABCD', 2))),
+ [('A','B'), ('A','C'), ('A','D'), ('B','C'), ('B','D'), ('C','D')])
+ testIntermediate = combinations('ABCD', 2)
+ next(testIntermediate)
+ self.assertEqual(list(op(testIntermediate)),
+ [('A','C'), ('A','D'), ('B','C'), ('B','D'), ('C','D')])
+
+ self.assertEqual(list(op(combinations(range(4), 3))),
+ [(0,1,2), (0,1,3), (0,2,3), (1,2,3)])
+ testIntermediate = combinations(range(4), 3)
+ next(testIntermediate)
+ self.assertEqual(list(op(testIntermediate)),
+ [(0,1,3), (0,2,3), (1,2,3)])
+

def combinations1(iterable, r):
'Pure python version shown in the docs'
@@ -168,6 +256,9 @@
self.assertEqual(result, list(combinations2(values, r))) # matches second pure python version
self.assertEqual(result, list(combinations3(values, r))) # matches second pure python version

+ self.pickletest(combinations(values, r)) # test pickling
+
+ # Test implementation detail: tuple re-use
@support.impl_detail("tuple reuse is specific to CPython")
def test_combinations_tuple_reuse(self):
self.assertEqual(len(set(map(id, combinations('abcde', 3)))), 1)
@@ -179,8 +270,15 @@
self.assertRaises(TypeError, cwr, 'abc', 2, 1) # too many arguments
self.assertRaises(TypeError, cwr, None) # pool is not iterable
self.assertRaises(ValueError, cwr, 'abc', -2) # r is negative
- self.assertEqual(list(cwr('ABC', 2)),
- [('A','A'), ('A','B'), ('A','C'), ('B','B'), ('B','C'), ('C','C')])
+
+ for op in (lambda a:a, lambda a:pickle.loads(pickle.dumps(a))):
+ self.assertEqual(list(op(cwr('ABC', 2))),
+ [('A','A'), ('A','B'), ('A','C'), ('B','B'), ('B','C'), ('C','C')])
+ testIntermediate = cwr('ABC', 2)
+ next(testIntermediate)
+ self.assertEqual(list(op(testIntermediate)),
+ [('A','B'), ('A','C'), ('B','B'), ('B','C'), ('C','C')])
+

def cwr1(iterable, r):
'Pure python version shown in the docs'
@@ -239,6 +337,10 @@
self.assertEqual(result, list(cwr1(values, r))) # matches first pure python version
self.assertEqual(result, list(cwr2(values, r))) # matches second pure python version

+ self.pickletest(cwr(values,r)) # test pickling
+
+ # Test implementation detail: tuple re-use
+
@support.impl_detail("tuple reuse is specific to CPython")
def test_combinations_with_replacement_tuple_reuse(self):
cwr = combinations_with_replacement
@@ -305,6 +407,8 @@
self.assertEqual(result, list(permutations(values, None))) # test r as None
self.assertEqual(result, list(permutations(values))) # test default r

+ self.pickletest(permutations(values, r)) # test pickling
+
@support.impl_detail("tuple resuse is CPython specific")
def test_permutations_tuple_reuse(self):
self.assertEqual(len(set(map(id, permutations('abcde', 3)))), 1)
@@ -359,6 +463,24 @@
self.assertRaises(TypeError, compress, range(6)) # too few args
self.assertRaises(TypeError, compress, range(6), None) # too many args

+ # check copy, deepcopy, pickle
+ for op in (lambda a:copy.copy(a), lambda a:copy.deepcopy(a), lambda a:pickle.loads(pickle.dumps(a))):
+ for data, selectors, result1, result2 in [
+ ('ABCDEF', [1,0,1,0,1,1], 'ACEF', 'CEF'),
+ ('ABCDEF', [0,0,0,0,0,0], '', ''),
+ ('ABCDEF', [1,1,1,1,1,1], 'ABCDEF', 'BCDEF'),
+ ('ABCDEF', [1,0,1], 'AC', 'C'),
+ ('ABC', [0,1,1,1,1,1], 'BC', 'C'),
+ ]:
+
+ self.assertEqual(list(op(compress(data=data, selectors=selectors))), list(result1))
+ self.assertEqual(list(op(compress(data, selectors))), list(result1))
+ testIntermediate = compress(data, selectors)
+ if result1:
+ next(testIntermediate)
+ self.assertEqual(list(op(testIntermediate)), list(result2))
+
+
def test_count(self):
self.assertEqual(lzip('abc',count()), [('a', 0), ('b', 1), ('c', 2)])
self.assertEqual(lzip('abc',count(3)), [('a', 3), ('b', 4), ('c', 5)])
@@ -393,7 +515,7 @@
c = count(value)
self.assertEqual(next(copy.copy(c)), value)
self.assertEqual(next(copy.deepcopy(c)), value)
- self.assertEqual(next(pickle.loads(pickle.dumps(c))), value)
+ self.pickletest(count(value))

#check proper internal error handling for large "step' sizes
count(1, maxsize+5); sys.exc_info()
@@ -440,6 +562,7 @@
else:
r2 = ('count(%r, %r)' % (i, j)).replace('L', '')
self.assertEqual(r1, r2)
+ self.pickletest(count(i, j))

def test_cycle(self):
self.assertEqual(take(10, cycle('abc')), list('abcabcabca'))
@@ -448,6 +571,18 @@
self.assertRaises(TypeError, cycle, 5)
self.assertEqual(list(islice(cycle(gen3()),10)), [0,1,2,0,1,2,0,1,2,0])

+ # check copy, deepcopy, pickle
+ c = cycle('abc')
+ self.assertEqual(next(c), 'a')
+ #simple copy currently not supported, because __reduce__ returns
+ #an internal iterator
+ #self.assertEqual(take(10, copy.copy(c)), list('bcabcabcab'))
+ self.assertEqual(take(10, copy.deepcopy(c)), list('bcabcabcab'))
+ self.assertEqual(take(10, pickle.loads(pickle.dumps(c))), list('bcabcabcab'))
+ next(c)
+ self.assertEqual(take(10, pickle.loads(pickle.dumps(c))), list('cabcabcabc'))
+ self.pickletest(cycle('abc'))
+
def test_groupby(self):
# Check whether it accepts arguments correctly
self.assertEqual([], list(groupby([])))
@@ -466,18 +601,37 @@
dup.append(elem)
self.assertEqual(s, dup)

+ # Check normal pickled
+ dup = []
+ for k, g in pickle.loads(pickle.dumps(groupby(s, testR))):
+ for elem in g:
+ self.assertEqual(k, elem[0])
+ dup.append(elem)
+ self.assertEqual(s, dup)
+
# Check nested case
dup = []
- for k, g in groupby(s, lambda r:r[0]):
- for ik, ig in groupby(g, lambda r:r[2]):
+ for k, g in groupby(s, testR):
+ for ik, ig in groupby(g, testR2):
for elem in ig:
self.assertEqual(k, elem[0])
self.assertEqual(ik, elem[2])
dup.append(elem)
self.assertEqual(s, dup)

+ # Check nested and pickled
+ dup = []
+ for k, g in pickle.loads(pickle.dumps(groupby(s, testR))):
+ for ik, ig in pickle.loads(pickle.dumps(groupby(g, testR2))):
+ for elem in ig:
+ self.assertEqual(k, elem[0])
+ self.assertEqual(ik, elem[2])
+ dup.append(elem)
+ self.assertEqual(s, dup)
+
+
# Check case where inner iterator is not used
- keys = [k for k, g in groupby(s, lambda r:r[0])]
+ keys = [k for k, g in groupby(s, testR)]
expectedkeys = set([r[0] for r in s])
self.assertEqual(set(keys), expectedkeys)
self.assertEqual(len(keys), len(expectedkeys))
@@ -548,6 +702,20 @@
self.assertRaises(TypeError, filter, isEven, 3)
self.assertRaises(TypeError, next, filter(range(6), range(6)))

+ # check copy, deepcopy, pickle
+ ans = [0,2,4]
+
+ c = filter(isEven, range(6))
+ self.assertEqual(list(copy.copy(c)), ans)
+ c = filter(isEven, range(6))
+ self.assertEqual(list(copy.deepcopy(c)), ans)
+ c = filter(isEven, range(6))
+ self.assertEqual(list(pickle.loads(pickle.dumps(c))), ans)
+ next(c)
+ self.assertEqual(list(pickle.loads(pickle.dumps(c))), ans[1:])
+ c = filter(isEven, range(6))
+ self.pickletest(c)
+
def test_filterfalse(self):
self.assertEqual(list(filterfalse(isEven, range(6))), [1,3,5])
self.assertEqual(list(filterfalse(None, [0,1,0,2,0])), [0,0,0])
@@ -558,6 +726,7 @@
self.assertRaises(TypeError, filterfalse, lambda x:x, range(6), 7)
self.assertRaises(TypeError, filterfalse, isEven, 3)
self.assertRaises(TypeError, next, filterfalse(range(6), range(6)))
+ self.pickletest(filterfalse(isEven, range(6)))

def test_zip(self):
# XXX This is rather silly now that builtin zip() calls zip()...
@@ -582,6 +751,23 @@
ids = list(map(id, list(zip('abc', 'def'))))
self.assertEqual(len(dict.fromkeys(ids)), len(ids))

+ # check copy, deepcopy, pickle
+ ans = [(x,y) for x, y in copy.copy(zip('abc',count()))]
+ self.assertEqual(ans, [('a', 0), ('b', 1), ('c', 2)])
+
+ ans = [(x,y) for x, y in copy.deepcopy(zip('abc',count()))]
+ self.assertEqual(ans, [('a', 0), ('b', 1), ('c', 2)])
+
+ ans = [(x,y) for x, y in pickle.loads(pickle.dumps(zip('abc',count())))]
+ self.assertEqual(ans, [('a', 0), ('b', 1), ('c', 2)])
+
+ testIntermediate = zip('abc',count())
+ next(testIntermediate)
+ ans = [(x,y) for x, y in pickle.loads(pickle.dumps(testIntermediate))]
+ self.assertEqual(ans, [('b', 1), ('c', 2)])
+
+ self.pickletest(zip('abc', count()))
+
def test_ziplongest(self):
for args in [
['abc', range(6)],
@@ -631,6 +817,12 @@
ids = list(map(id, list(zip_longest('abc', 'def'))))
self.assertEqual(len(dict.fromkeys(ids)), len(ids))

+ def test_zip_longest_pickling(self):
+ self.pickletest(zip_longest("abc", "def"))
+ self.pickletest(zip_longest("abc", "defgh"))
+ self.pickletest(zip_longest("abc", "defgh", fillvalue=1))
+ self.pickletest(zip_longest("", "defgh"))
+
def test_bug_7244(self):

class Repeater:
@@ -734,6 +926,20 @@
self.assertEqual(len(set(map(id, product('abc', 'def')))), 1)
self.assertNotEqual(len(set(map(id, list(product('abc', 'def'))))), 1)

+ def test_product_pickling(self):
+ # check copy, deepcopy, pickle
+ for args, result in [
+ ([], [()]), # zero iterables
+ (['ab'], [('a',), ('b',)]), # one iterable
+ ([range(2), range(3)], [(0,0), (0,1), (0,2), (1,0), (1,1), (1,2)]), # two iterables
+ ([range(0), range(2), range(3)], []), # first iterable with zero length
+ ([range(2), range(0), range(3)], []), # middle iterable with zero length
+ ([range(2), range(3), range(0)], []), # last iterable with zero length
+ ]:
+ self.assertEqual(list(copy.copy(product(*args))), result)
+ self.assertEqual(list(copy.deepcopy(product(*args))), result)
+ self.pickletest(product(*args))
+
def test_repeat(self):
self.assertEqual(list(repeat(object='a', times=3)), ['a', 'a', 'a'])
self.assertEqual(lzip(range(3),repeat('a')),
@@ -752,11 +958,16 @@
list(r)
self.assertEqual(repr(r), 'repeat((1+0j), 0)')

+ # check copy, deepcopy, pickle
+ c = repeat(object='a', times=10)
+ self.assertEqual(next(c), 'a')
+ self.assertEqual(take(2, copy.copy(c)), list('a' * 2))
+ self.assertEqual(take(2, copy.deepcopy(c)), list('a' * 2))
+ self.pickletest(repeat(object='a', times=10))
+
def test_map(self):
self.assertEqual(list(map(operator.pow, range(3), range(1,7))),
[0**1, 1**2, 2**3])
- def tupleize(*args):
- return args
self.assertEqual(list(map(tupleize, 'abc', range(5))),
[('a',0),('b',1),('c',2)])
self.assertEqual(list(map(tupleize, 'abc', count())),
@@ -771,6 +982,18 @@
self.assertRaises(ValueError, next, map(errfunc, [4], [5]))
self.assertRaises(TypeError, next, map(onearg, [4], [5]))

+ # check copy, deepcopy, pickle
+ ans = [('a',0),('b',1),('c',2)]
+
+ c = map(tupleize, 'abc', count())
+ self.assertEqual(list(copy.copy(c)), ans)
+
+ c = map(tupleize, 'abc', count())
+ self.assertEqual(list(copy.deepcopy(c)), ans)
+
+ c = map(tupleize, 'abc', count())
+ self.pickletest(c)
+
def test_starmap(self):
self.assertEqual(list(starmap(operator.pow, zip(range(3), range(1,7)))),
[0**1, 1**2, 2**3])
@@ -785,6 +1008,18 @@
self.assertRaises(ValueError, next, starmap(errfunc, [(4,5)]))
self.assertRaises(TypeError, next, starmap(onearg, [(4,5)]))

+ # check copy, deepcopy, pickle
+ ans = [0**1, 1**2, 2**3]
+
+ c = starmap(operator.pow, zip(range(3), range(1,7)))
+ self.assertEqual(list(copy.copy(c)), ans)
+
+ c = starmap(operator.pow, zip(range(3), range(1,7)))
+ self.assertEqual(list(copy.deepcopy(c)), ans)
+
+ c = starmap(operator.pow, zip(range(3), range(1,7)))
+ self.pickletest(c)
+
def test_islice(self):
for args in [. # islice(args) should agree with range(args)
(10, 20, 3),
@@ -817,17 +1052,18 @@
self.assertEqual(list(it), list(range(3, 10)))

# Test invalid arguments
- self.assertRaises(TypeError, islice, range(10))
- self.assertRaises(TypeError, islice, range(10), 1, 2, 3, 4)
- self.assertRaises(ValueError, islice, range(10), -5, 10, 1)
- self.assertRaises(ValueError, islice, range(10), 1, -5, -1)
- self.assertRaises(ValueError, islice, range(10), 1, 10, -1)
- self.assertRaises(ValueError, islice, range(10), 1, 10, 0)
- self.assertRaises(ValueError, islice, range(10), 'a')
- self.assertRaises(ValueError, islice, range(10), 'a', 1)
- self.assertRaises(ValueError, islice, range(10), 1, 'a')
- self.assertRaises(ValueError, islice, range(10), 'a', 1, 1)
- self.assertRaises(ValueError, islice, range(10), 1, 'a', 1)
+ ra = range(10)
+ self.assertRaises(TypeError, islice, ra)
+ self.assertRaises(TypeError, islice, ra, 1, 2, 3, 4)
+ self.assertRaises(ValueError, islice, ra, -5, 10, 1)
+ self.assertRaises(ValueError, islice, ra, 1, -5, -1)
+ self.assertRaises(ValueError, islice, ra, 1, 10, -1)
+ self.assertRaises(ValueError, islice, ra, 1, 10, 0)
+ self.assertRaises(ValueError, islice, ra, 'a')
+ self.assertRaises(ValueError, islice, ra, 'a', 1)
+ self.assertRaises(ValueError, islice, ra, 1, 'a')
+ self.assertRaises(ValueError, islice, ra, 'a', 1, 1)
+ self.assertRaises(ValueError, islice, ra, 1, 'a', 1)
self.assertEqual(len(list(islice(count(), 1, 10, maxsize))), 1)

# Issue #10323: Less islice in a predictable state
@@ -835,9 +1071,22 @@
self.assertEqual(list(islice(c, 1, 3, 50)), [1])
self.assertEqual(next(c), 3)

+ # check copy, deepcopy, pickle
+ for args in [. # islice(args) should agree with range(args)
+ (10, 20, 3),
+ (10, 3, 20),
+ (10, 20),
+ (10, 3),
+ (20,)
+ ]:
+ self.assertEqual(list(copy.copy(islice(range(100), *args))),
+ list(range(*args)))
+ self.assertEqual(list(copy.deepcopy(islice(range(100), *args))),
+ list(range(*args)))
+ self.pickletest(islice(range(100), *args))
+
def test_takewhile(self):
data = [1, 3, 5, 20, 2, 4, 6, 8]
- underten = lambda x: x<10
self.assertEqual(list(takewhile(underten, data)), [1, 3, 5])
self.assertEqual(list(takewhile(underten, [])), [])
self.assertRaises(TypeError, takewhile)
@@ -849,9 +1098,14 @@
self.assertEqual(list(t), [1, 1, 1])
self.assertRaises(StopIteration, next, t)

+ # check copy, deepcopy, pickle
+ self.assertEqual(list(copy.copy(takewhile(underten, data))), [1, 3, 5])
+ self.assertEqual(list(copy.deepcopy(takewhile(underten, data))),
+ [1, 3, 5])
+ self.pickletest(takewhile(underten, data))
+
def test_dropwhile(self):
data = [1, 3, 5, 20, 2, 4, 6, 8]
- underten = lambda x: x<10
self.assertEqual(list(dropwhile(underten, data)), [20, 2, 4, 6, 8])
self.assertEqual(list(dropwhile(underten, [])), [])
self.assertRaises(TypeError, dropwhile)
@@ -860,11 +1114,14 @@
self.assertRaises(TypeError, next, dropwhile(10, [(4,5)]))
self.assertRaises(ValueError, next, dropwhile(errfunc, [(4,5)]))

+ # check copy, deepcopy, pickle
+ self.assertEqual(list(copy.copy(dropwhile(underten, data))), [20, 2, 4, 6, 8])
+ self.assertEqual(list(copy.deepcopy(dropwhile(underten, data))),
+ [20, 2, 4, 6, 8])
+ self.pickletest(dropwhile(underten, data))
+
def test_tee(self):
n = 200
- def irange(n):
- for i in range(n):
- yield i

a, b = tee([]) # test empty iterator
self.assertEqual(list(a), [])
@@ -949,6 +1206,67 @@
del a
self.assertRaises(ReferenceError, getattr, p, '__class__')

+ ans = list('abc')
+ long_ans = list(range(10000))
+
+ # check copy
+ a, b = tee('abc')
+ self.assertEqual(list(copy.copy(a)), ans)
+ self.assertEqual(list(copy.copy(b)), ans)
+ a, b = tee(list(range(10000)))
+ self.assertEqual(list(copy.copy(a)), long_ans)
+ self.assertEqual(list(copy.copy(b)), long_ans)
+
+ # check partially consumed copy
+ a, b = tee('abc')
+ take(2, a)
+ take(1, b)
+ self.assertEqual(list(copy.copy(a)), ans[2:])
+ self.assertEqual(list(copy.copy(b)), ans[1:])
+ self.assertEqual(list(a), ans[2:])
+ self.assertEqual(list(b), ans[1:])
+ a, b = tee(range(10000))
+ take(100, a)
+ take(60, b)
+ self.assertEqual(list(copy.copy(a)), long_ans[100:])
+ self.assertEqual(list(copy.copy(b)), long_ans[60:])
+ self.assertEqual(list(a), long_ans[100:])
+ self.assertEqual(list(b), long_ans[60:])
+
+ # check deepcopy
+ a, b = tee('abc')
+ self.assertEqual(list(copy.deepcopy(a)), ans)
+ self.assertEqual(list(copy.deepcopy(b)), ans)
+ self.assertEqual(list(a), ans)
+ self.assertEqual(list(b), ans)
+ a, b = tee(range(10000))
+ self.assertEqual(list(copy.deepcopy(a)), long_ans)
+ self.assertEqual(list(copy.deepcopy(b)), long_ans)
+ self.assertEqual(list(a), long_ans)
+ self.assertEqual(list(b), long_ans)
+
+ # check partially consumed deepcopy
+ a, b = tee('abc')
+ take(2, a)
+ take(1, b)
+ self.assertEqual(list(copy.deepcopy(a)), ans[2:])
+ self.assertEqual(list(copy.deepcopy(b)), ans[1:])
+ self.assertEqual(list(a), ans[2:])
+ self.assertEqual(list(b), ans[1:])
+ a, b = tee(range(10000))
+ take(100, a)
+ take(60, b)
+ self.assertEqual(list(copy.deepcopy(a)), long_ans[100:])
+ self.assertEqual(list(copy.deepcopy(b)), long_ans[60:])
+ self.assertEqual(list(a), long_ans[100:])
+ self.assertEqual(list(b), long_ans[60:])
+
+ # check pickle
+ self.pickletest(iter(tee('abc')))
+ a, b = tee('abc')
+ self.pickletest(a, compare=ans)
+ self.pickletest(b, compare=ans)
+
def test_StopIteration(self):
self.assertRaises(StopIteration, next, zip())

@@ -974,9 +1292,21 @@

class TestExamples(unittest.TestCase):

- def test_accumlate(self):
+ def test_accumulate(self):
self.assertEqual(list(accumulate([1,2,3,4,5])), [1, 3, 6, 10, 15])

+ def test_accumulate_reducible(self):
+ # check copy, deepcopy, pickle
+ data = [1, 2, 3, 4, 5]
+ accumulated = [1, 3, 6, 10, 15]
+ it = accumulate(data)
+
+ self.assertEqual(list(pickle.loads(pickle.dumps(it))), accumulated[:])
+ self.assertEqual(next(it), 1)
+ self.assertEqual(list(pickle.loads(pickle.dumps(it))), accumulated[1:])
+ self.assertEqual(list(copy.deepcopy(it)), accumulated[1:])
+ self.assertEqual(list(copy.copy(it)), accumulated[1:])
+
def test_chain(self):
self.assertEqual(''.join(chain('ABC', 'DEF')), 'ABCDEF')

diff --git a/Lib/test/test_list.py b/Lib/test/test_list.py
--- a/Lib/test/test_list.py
+++ b/Lib/test/test_list.py
@@ -1,5 +1,6 @@
import sys
from test import support, list_tests
+import pickle

class ListTest(list_tests.CommonTest):
type2test = list
@@ -69,6 +70,33 @@
check(10) # check our checking code
check(1000000)

+ def test_iterator_pickle(self):
+ # Userlist iterators don't support pickling yet since
+ # they are based on generators.
+ data = self.type2test([4, 5, 6, 7])
+ it = itorg = iter(data)
+ d = pickle.dumps(it)
+ it = pickle.loads(d)
+ self.assertEqual(type(itorg), type(it))
+ self.assertEqual(self.type2test(it), self.type2test(data))
+
+ it = pickle.loads(d)
+ next(it)
+ d = pickle.dumps(it)
+ self.assertEqual(self.type2test(it), self.type2test(data)[1:])
+
+ def test_reversed_pickle(self):
+ data = self.type2test([4, 5, 6, 7])
+ it = itorg = reversed(data)
+ d = pickle.dumps(it)
+ it = pickle.loads(d)
+ self.assertEqual(type(itorg), type(it))
+ self.assertEqual(self.type2test(it), self.type2test(reversed(data)))
+
+ it = pickle.loads(d)
+ next(it)
+ d = pickle.dumps(it)
+ self.assertEqual(self.type2test(it), self.type2test(reversed(data))[1:])

def test_main(verbose=None):
support.run_unittest(ListTest)
diff --git a/Lib/test/test_multiprocessing.py b/Lib/test/test_multiprocessing.py
--- a/Lib/test/test_multiprocessing.py
+++ b/Lib/test/test_multiprocessing.py
@@ -2649,6 +2649,10 @@
with self.assertRaises(ValueError):
multiprocessing.connection.Listener(r'\\.\test')

+ @unittest.skipUnless(WIN32, "skipped on non-Windows platforms")
+ def test_invalid_family_win32(self):
+ with self.assertRaises(ValueError):
+ multiprocessing.connection.Listener('/var/test.pipe')

testcases_other = [OtherTest, TestInvalidHandle, TestInitializers,
TestStdinBadfiledescriptor, TestWait, TestInvalidFamily]
diff --git a/Lib/test/test_range.py b/Lib/test/test_range.py
--- a/Lib/test/test_range.py
+++ b/Lib/test/test_range.py
@@ -341,13 +341,35 @@

def test_pickling(self):
testcases = [.(13,), (0, 11), (-22, 10), (20, 3, -1),
- (13, 21, 3), (-2, 2, 2)]
+ (13, 21, 3), (-2, 2, 2), (2**65, 2**65+2)]
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
for t in testcases:
r = range(*t)
self.assertEqual(list(pickle.loads(pickle.dumps(r, proto))),
list(r))

+ def test_iterator_pickling(self):
+ testcases = [.(13,), (0, 11), (-22, 10), (20, 3, -1),
+ (13, 21, 3), (-2, 2, 2), (2**65, 2**65+2)]
+ for proto in range(pickle.HIGHEST_PROTOCOL + 1):
+ for t in testcases:
+ it = itorg = iter(range(*t))
+ data = list(range(*t))
+
+ d = pickle.dumps(it)
+ it = pickle.loads(d)
+ self.assertEqual(type(itorg), type(it))
+ self.assertEqual(list(it), data)
+
+ it = pickle.loads(d)
+ try:
+ next(it)
+ except StopIteration:
+ continue
+ d = pickle.dumps(it)
+ it = pickle.loads(d)
+ self.assertEqual(list(it), data[1:])
+
def test_odd_bug(self):
# This used to raise a "SystemError: NULL result without error"
# because the range validation step was eating the exception
diff --git a/Lib/test/test_set.py b/Lib/test/test_set.py
--- a/Lib/test/test_set.py
+++ b/Lib/test/test_set.py
@@ -9,6 +9,7 @@
import sys
import warnings
import collections
+import collections.abc

class PassThru(Exception):
pass
@@ -234,6 +235,26 @@
dup = pickle.loads(p)
self.assertEqual(self.s.x, dup.x)

+ def test_iterator_pickling(self):
+ itorg = iter(self.s)
+ data = self.thetype(self.s)
+ d = pickle.dumps(itorg)
+ it = pickle.loads(d)
+ # Set iterators unpickle as list iterators due to the
+ # undefined order of set items.
+ # self.assertEqual(type(itorg), type(it))
+ self.assertTrue(isinstance(it, collections.abc.Iterator))
+ self.assertEqual(self.thetype(it), data)
+
+ it = pickle.loads(d)
+ try:
+ drop = next(it)
+ except StopIteration:
+ return
+ d = pickle.dumps(it)
+ it = pickle.loads(d)
+ self.assertEqual(self.thetype(it), data - self.thetype((drop,)))
+
def test_deepcopy(self):
class Tracer:
def __init__(self, value):
diff --git a/Lib/test/test_tools.py b/Lib/test/test_tools.py
--- a/Lib/test/test_tools.py
+++ b/Lib/test/test_tools.py
@@ -5,8 +5,11 @@
"""

import os
+import sys
+import imp
import unittest
import sysconfig
+import tempfile
from test import support
from test.script_helper import assert_python_ok

@@ -17,10 +20,11 @@

srcdir = sysconfig.get_config_var('projectbase')
basepath = os.path.join(os.getcwd(), srcdir, 'Tools')
+scriptsdir = os.path.join(basepath, 'scripts')


class ReindentTests(unittest.TestCase):
- script = os.path.join(basepath, 'scripts', 'reindent.py')
+ script = os.path.join(scriptsdir, 'reindent.py')

def test_noargs(self):
assert_python_ok(self.script)
@@ -31,8 +35,73 @@
self.assertGreater(err, b'')


+class TestSundryScripts(unittest.TestCase):
+ # At least make sure the rest don't have syntax errors. When tests are
+ # added for a script it should be added to the whitelist below.
+
+ # scripts that have independent tests.
+ whitelist = ['reindent.py']
+ # scripts that can't be imported without running
+ blacklist = ['make_ctype.py']
+ # scripts that use windows-only modules
+ windows_only = ['win_add2path.py']
+ # blacklisted for other reasons
+ other = ['analyze_dxp.py']
+
+ skiplist = blacklist + whitelist + windows_only + other
+
+ def setUp(self):
+ cm = support.DirsOnSysPath(scriptsdir)
+ cm.__enter__()
+ self.addCleanup(cm.__exit__)
+
+ def test_sundry(self):
+ for fn in os.listdir(scriptsdir):
+ if fn.endswith('.py') and fn not in self.skiplist:
+ __import__(fn[:-3])
+
+ @unittest.skipIf(sys.platform != "win32", "Windows-only test")
+ def test_sundry_windows(self):
+ for fn in self.windows_only:
+ __import__(fn[:-3])
+
+ @unittest.skipIf(not support.threading, "test requires _thread module")
+ def test_analyze_dxp_import(self):
+ if hasattr(sys, 'getdxp'):
+ import analyze_dxp
+ else:
+ with self.assertRaises(RuntimeError):
+ import analyze_dxp
+
+
+class PdepsTests(unittest.TestCase):
+
+ @classmethod
+ def setUpClass(self):
+ path = os.path.join(scriptsdir, 'pdeps.py')
+ self.pdeps = imp.load_source('pdeps', path)
+
+ @classmethod
+ def tearDownClass(self):
+ if 'pdeps' in sys.modules:
+ del sys.modules['pdeps']
+
+ def test_process_errors(self):
+ # Issue #14492: m_import.match(line) can be None.
+ with tempfile.TemporaryDirectory() as tmpdir:
+ fn = os.path.join(tmpdir, 'foo')
+ with open(fn, 'w') as stream:
+ stream.write("#!/this/will/fail")
+ self.pdeps.process(fn, {})
+
+ def test_inverse_attribute_error(self):
+ # Issue #14492: this used to fail with an AttributeError.
+ self.pdeps.inverse({'a': []})
+
+
def test_main():
- support.run_unittest(ReindentTests)
+ support.run_unittest(*[obj for obj in globals().values()
+ if isinstance(obj, type)])


if __name__ == '__main__':
diff --git a/Lib/test/test_tuple.py b/Lib/test/test_tuple.py
--- a/Lib/test/test_tuple.py
+++ b/Lib/test/test_tuple.py
@@ -1,6 +1,7 @@
from test import support, seq_tests

import gc
+import pickle

class TupleTest(seq_tests.CommonTest):
type2test = tuple
@@ -164,6 +165,34 @@
check(10) # check our checking code
check(1000000)

+ def test_iterator_pickle(self):
+ # Userlist iterators don't support pickling yet since
+ # they are based on generators.
+ data = self.type2test([4, 5, 6, 7])
+ itorg = iter(data)
+ d = pickle.dumps(itorg)
+ it = pickle.loads(d)
+ self.assertEqual(type(itorg), type(it))
+ self.assertEqual(self.type2test(it), self.type2test(data))
+
+ it = pickle.loads(d)
+ next(it)
+ d = pickle.dumps(it)
+ self.assertEqual(self.type2test(it), self.type2test(data)[1:])
+
+ def test_reversed_pickle(self):
+ data = self.type2test([4, 5, 6, 7])
+ itorg = reversed(data)
+ d = pickle.dumps(itorg)
+ it = pickle.loads(d)
+ self.assertEqual(type(itorg), type(it))
+ self.assertEqual(self.type2test(it), self.type2test(reversed(data)))
+
+ it = pickle.loads(d)
+ next(it)
+ d = pickle.dumps(it)
+ self.assertEqual(self.type2test(it), self.type2test(reversed(data))[1:])
+
def test_main():
support.run_unittest(TupleTest)

diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py
--- a/Lib/test/test_xml_etree.py
+++ b/Lib/test/test_xml_etree.py
@@ -1859,6 +1859,41 @@
gc_collect()
self.assertIsNone(wref())

+ # A longer cycle: d->e->e2->d
+ e = ET.Element('joe')
+ d = Dummy()
+ d.dummyref = e
+ wref = weakref.ref(d)
+ e2 = ET.SubElement(e, 'foo', attr=d)
+ del d, e, e2
+ gc_collect()
+ self.assertIsNone(wref())
+
+ # A cycle between Element objects as children of one another
+ # e1->e2->e3->e1
+ e1 = ET.Element('e1')
+ e2 = ET.Element('e2')
+ e3 = ET.Element('e3')
+ e1.append(e2)
+ e2.append(e2)
+ e3.append(e1)
+ wref = weakref.ref(e1)
+ del e1, e2, e3
+ gc_collect()
+ self.assertIsNone(wref())
+
+ def test_weakref(self):
+ flag = False
+ def wref_cb(w):
+ nonlocal flag
+ flag = True
+ e = ET.Element('e')
+ wref = weakref.ref(e, wref_cb)
+ self.assertEqual(wref().tag, 'e')
+ del e
+ self.assertEqual(flag, True)
+ self.assertEqual(wref(), None)
+

class ElementTreeTest(unittest.TestCase):
def test_istype(self):
diff --git a/Lib/tkinter/font.py b/Lib/tkinter/font.py
--- a/Lib/tkinter/font.py
+++ b/Lib/tkinter/font.py
@@ -2,27 +2,27 @@
#
# written by Fredrik Lundh, February 1998
#
-# FIXME: should add 'displayof' option where relevant (actual, families,
-# measure, and metrics)
-#

__version__ = "0.9"

+import itertools
import tkinter

+
# weight/slant
NORMAL = "normal"
ROMAN = "roman"
BOLD = "bold"
ITALIC = "italic"

+
def nametofont(name):
"""Given the name of a tk named font, returns a Font representation.
"""
return Font(name=name, exists=True)

+
class Font:
-
"""Represents a named font.

Constructor options are:
@@ -44,6 +44,8 @@

"""

+ counter = itertools.count(1)
+
def _set(self, kw):
options = []
for k, v in kw.items():
@@ -63,7 +65,8 @@
options[args[i][1:]] = args[i+1]
return options

- def __init__(self, root=None, font=None, name=None, exists=False, **options):
+ def __init__(self, root=None, font=None, name=None, exists=False,
+ **options):
if not root:
root = tkinter._default_root
if font:
@@ -72,7 +75,7 @@
else:
font = self._set(options)
if not name:
- name = "font" + str(id(self))
+ name = "font" + str(next(self.counter))
self.name = name

if exists:
@@ -118,14 +121,17 @@
"Return a distinct copy of the current font"
return Font(self._root, **self.actual())

- def actual(self, option=None):
+ def actual(self, option=None, displayof=None):
"Return actual font attributes"
+ args = ()
+ if displayof:
+ args = ('-displayof', displayof)
if option:
- return self._call("font", "actual", self.name, "-"+option)
+ args = args + ('-' + option, )
+ return self._call("font", "actual", self.name, *args)
else:
return self._mkdict(
- self._split(self._call("font", "actual", self.name))
- )
+ self._split(self._call("font", "actual", self.name, *args)))

def cget(self, option):
"Get font attribute"
@@ -138,37 +144,47 @@
*self._set(options))
else:
return self._mkdict(
- self._split(self._call("font", "config", self.name))
- )
+ self._split(self._call("font", "config", self.name)))

configure = config

- def measure(self, text):
+ def measure(self, text, displayof=None):
"Return text width"
- return int(self._call("font", "measure", self.name, text))
+ args = (text,)
+ if displayof:
+ args = ('-displayof', displayof, text)
+ return int(self._call("font", "measure", self.name, *args))

- def metrics(self, *options):
+ def metrics(self, *options, **kw):
"""Return font metrics.

For best performance, create a dummy widget
using this font before calling this method."""
-
+ args = ()
+ displayof = kw.pop('displayof', None)
+ if displayof:
+ args = ('-displayof', displayof)
if options:
+ args = args + self._get(options)
return int(
- self._call("font", "metrics", self.name, self._get(options))
- )
+ self._call("font", "metrics", self.name, *args))
else:
- res = self._split(self._call("font", "metrics", self.name))
+ res = self._split(self._call("font", "metrics", self.name, *args))
options = {}
for i in range(0, len(res), 2):
options[res[i][1:]] = int(res[i+1])
return options

-def families(root=None):
+
+def families(root=None, displayof=None):
"Get font families (as a tuple)"
if not root:
root = tkinter._default_root
- return root.tk.splitlist(root.tk.call("font", "families"))
+ args = ()
+ if displayof:
+ args = ('-displayof', displayof)
+ return root.tk.splitlist(root.tk.call("font", "families", *args))
+

def names(root=None):
"Get names of defined fonts (as a tuple)"
@@ -176,6 +192,7 @@
root = tkinter._default_root
return root.tk.splitlist(root.tk.call("font", "names"))

+
# --------------------------------------------------------------------
# test stuff

@@ -198,10 +215,10 @@

print(f.measure("hello"), f.metrics("linespace"))

- print(f.metrics())
+ print(f.metrics(displayof=root))

f = Font(font=("Courier", 20, "bold"))
- print(f.measure("hello"), f.metrics("linespace"))
+ print(f.measure("hello"), f.metrics("linespace", displayof=root))

w = tkinter.Label(root, text="Hello, world", font=f)
w.pack()
diff --git a/Lib/tkinter/ttk.py b/Lib/tkinter/ttk.py
--- a/Lib/tkinter/ttk.py
+++ b/Lib/tkinter/ttk.py
@@ -1253,7 +1253,7 @@


def exists(self, item):
- """Returns True if the specified item is present in the three,
+ """Returns True if the specified item is present in the tree,
False otherwise."""
return bool(self.tk.call(self._w, "exists", item))

diff --git a/Lib/webbrowser.py b/Lib/webbrowser.py
--- a/Lib/webbrowser.py
+++ b/Lib/webbrowser.py
@@ -448,6 +448,14 @@

def register_X_browsers():

+ # use xdg-open if around
+ if _iscommand("xdg-open"):
+ register("xdg-open", None, BackgroundBrowser("xdg-open"))
+
+ # The default GNOME3 browser
+ if "GNOME_DESKTOP_SESSION_ID" in os.environ and _iscommand("gvfs-open"):
+ register("gvfs-open", None, BackgroundBrowser("gvfs-open"))
+
# The default GNOME browser
if "GNOME_DESKTOP_SESSION_ID" in os.environ and _iscommand("gnome-open"):
register("gnome-open", None, BackgroundBrowser("gnome-open"))
diff --git a/Makefile.pre.in b/Makefile.pre.in
--- a/Makefile.pre.in
+++ b/Makefile.pre.in
@@ -1351,7 +1351,7 @@

clobber: clean profile-removal
-rm -f $(BUILDPYTHON) $(PGEN) $(LIBRARY) $(LDLIBRARY) $(DLLLIBRARY) \
- tags TAGS Parser/pgen.stamp \
+ tags TAGS \
config.cache config.log pyconfig.h Modules/config.c
-rm -rf build platform
-rm -rf $(PYTHONFRAMEWORKDIR)
diff --git a/Misc/ACKS b/Misc/ACKS
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -333,6 +333,7 @@
John Fouhy
Andrew Francis
Martin Franklin
+Bruce Frederiksen
Robin Friedrich
Ivan Frohne
Matthias Fuchs
@@ -976,6 +977,7 @@
Peter Stoehr
Casper Stoel
Michael Stone
+Serhiy Storchaka
Ken Stox
Dan Stromberg
Daniel Stutzbach
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -19,10 +19,26 @@
Library
-------

+- Issue #8515: Set __file__ when run file in IDLE.
+ Initial patch by Bruce Frederiksen.
+
+- Issue #14496: Fix wrong name in idlelib/tabbedpages.py.
+ Patch by Popa Claudiu.
+
+- Issue #3033: Add displayof parameter to tkinter font. Patch by Guilherme Polo.
+
+- Issue #14482: Raise a ValueError, not a NameError, when trying to create
+ a multiprocessing Client or Listener with an AF_UNIX type address under
+ Windows. Patch by Popa Claudiu.
+
+- Issue #802310: Generate always unique tkinter font names if not directly passed.
+
- Issue #14151: Raise a ValueError, not a NameError, when trying to create
a multiprocessing Client or Listener with an AF_PIPE type address under
non-Windows platforms. Patch by Popa Claudiu.

+- Issue #14493: Use gvfs-open or xdg-open in webbrowser.
+

What's New in Python 3.3.0 Alpha 2?
===================================
@@ -58,6 +74,8 @@

- Issue #14471: Fix a possible buffer overrun in the winreg module.

+- Issue #14288: Allow the serialization of builtin iterators
+
Library
-------

@@ -997,7 +1015,7 @@

- Issue #11006: Don't issue low level warning in subprocess when pipe2() fails.

-- Issue #13620: Support for Chrome browser in webbrowser.py Patch contributed
+- Issue #13620: Support for Chrome browser in webbrowser. Patch contributed
by Arnaud Calmettes.

- Issue #11829: Fix code execution holes in inspect.getattr_static for
diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c
--- a/Modules/_collectionsmodule.c
+++ b/Modules/_collectionsmodule.c
@@ -1122,6 +1122,35 @@
}

static PyObject *
+dequeiter_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ Py_ssize_t i, index=0;
+ PyObject *deque;
+ dequeiterobject *it;
+ if (!PyArg_ParseTuple(args, "O!|n", &deque_type, &deque, &index))
+ return NULL;
+ assert(type == &dequeiter_type);
+
+ it = (dequeiterobject*)deque_iter((dequeobject *)deque);
+ if (!it)
+ return NULL;
+ /* consume items from the queue */
+ for(i=0; i<index; i++) {
+ PyObject *item = dequeiter_next(it);
+ if (item) {
+ Py_DECREF(item);
+ } else {
+ if (it->counter) {
+ Py_DECREF(it);
+ return NULL;
+ } else
+ break;
+ }
+ }
+ return (PyObject*)it;
+}
+
+static PyObject *
dequeiter_len(dequeiterobject *it)
{
return PyLong_FromSsize_t(it->counter);
@@ -1129,14 +1158,21 @@

PyDoc_STRVAR(length_hint_doc, "Private method returning an estimate of len(list(it)).");

+static PyObject *
+dequeiter_reduce(dequeiterobject *it)
+{
+ return Py_BuildValue("O(On)", Py_TYPE(it), it->deque, it->deque->len - it->counter);
+}
+
static PyMethodDef dequeiter_methods[] = {
{"__length_hint__", (PyCFunction)dequeiter_len, METH_NOARGS, length_hint_doc},
+ {"__reduce__", (PyCFunction)dequeiter_reduce, METH_NOARGS, reduce_doc},
{NULL, NULL} /* sentinel */
};

static PyTypeObject dequeiter_type = {
PyVarObject_HEAD_INIT(NULL, 0)
- "deque_iterator", /* tp_name */
+ "_collections._deque_iterator", /* tp_name */
sizeof(dequeiterobject), /* tp_basicsize */
0, /* tp_itemsize */
/* methods */
@@ -1164,6 +1200,16 @@
PyObject_SelfIter, /* tp_iter */
(iternextfunc)dequeiter_next, /* tp_iternext */
dequeiter_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ dequeiter_new, /* tp_new */
0,
};

@@ -1217,9 +1263,38 @@
return item;
}

+static PyObject *
+dequereviter_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ Py_ssize_t i, index=0;
+ PyObject *deque;
+ dequeiterobject *it;
+ if (!PyArg_ParseTuple(args, "O!|n", &deque_type, &deque, &index))
+ return NULL;
+ assert(type == &dequereviter_type);
+
+ it = (dequeiterobject*)deque_reviter((dequeobject *)deque);
+ if (!it)
+ return NULL;
+ /* consume items from the queue */
+ for(i=0; i<index; i++) {
+ PyObject *item = dequereviter_next(it);
+ if (item) {
+ Py_DECREF(item);
+ } else {
+ if (it->counter) {
+ Py_DECREF(it);
+ return NULL;
+ } else
+ break;
+ }
+ }
+ return (PyObject*)it;
+}
+
static PyTypeObject dequereviter_type = {
PyVarObject_HEAD_INIT(NULL, 0)
- "deque_reverse_iterator", /* tp_name */
+ "_collections._deque_reverse_iterator", /* tp_name */
sizeof(dequeiterobject), /* tp_basicsize */
0, /* tp_itemsize */
/* methods */
@@ -1247,6 +1322,16 @@
PyObject_SelfIter, /* tp_iter */
(iternextfunc)dequereviter_next, /* tp_iternext */
dequeiter_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ dequereviter_new, /* tp_new */
0,
};

@@ -1653,9 +1738,13 @@

if (PyType_Ready(&dequeiter_type) < 0)
return NULL;
+ Py_INCREF(&dequeiter_type);
+ PyModule_AddObject(m, "_deque_iterator", (PyObject *)&dequeiter_type);

if (PyType_Ready(&dequereviter_type) < 0)
return NULL;
+ Py_INCREF(&dequereviter_type);
+ PyModule_AddObject(m, "_deque_reverse_iterator", (PyObject *)&dequereviter_type);

return m;
}
diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c
--- a/Modules/_decimal/_decimal.c
+++ b/Modules/_decimal/_decimal.c
@@ -1935,7 +1935,7 @@
mpd_maxcontext(&maxctx);

mpd_qset_string(MPD(dec), s, &maxctx, &status);
- if (status & (MPD_Inexact|MPD_Rounded)) {
+ if (status & (MPD_Inexact|MPD_Rounded|MPD_Clamped)) {
/* we want exact results */
mpd_seterror(MPD(dec), MPD_Invalid_operation, &status);
}
@@ -2139,7 +2139,7 @@
return NULL;
}

- if (status & (MPD_Inexact|MPD_Rounded)) {
+ if (status & (MPD_Inexact|MPD_Rounded|MPD_Clamped)) {
/* we want exact results */
mpd_seterror(MPD(dec), MPD_Invalid_operation, &status);
}
@@ -2385,8 +2385,8 @@
}

/* coefficient */
- digits = sequence_as_tuple(PyTuple_GET_ITEM(dectuple, 1),
- PyExc_ValueError, "coefficient must be a tuple of digits");
+ digits = sequence_as_tuple(PyTuple_GET_ITEM(dectuple, 1), PyExc_ValueError,
+ "coefficient must be a tuple of digits");
if (digits == NULL) {
goto error;
}
@@ -2435,8 +2435,8 @@
if (sign_special[1] == '\0') {
/* not a special number */
*cp++ = 'E';
- n = snprintf(cp, MPD_EXPDIGITS+1, "%" PRI_mpd_ssize_t, exp);
- if (n < 0 || n >= MPD_EXPDIGITS+1) {
+ n = snprintf(cp, MPD_EXPDIGITS+2, "%" PRI_mpd_ssize_t, exp);
+ if (n < 0 || n >= MPD_EXPDIGITS+2) {
PyErr_SetString(PyExc_RuntimeError,
"internal error in dec_sequence_as_str");
goto error;
@@ -4215,7 +4215,7 @@
mpd_uint_t p_data[1] = {2305843009213693951ULL};
mpd_t p = {MPD_POS|MPD_STATIC|MPD_CONST_DATA, 0, 19, 1, 1, p_data};
/* Inverse of 10 modulo p */
- mpd_uint_t inv10_p_data[2] = {2075258708292324556ULL};
+ mpd_uint_t inv10_p_data[1] = {2075258708292324556ULL};
mpd_t inv10_p = {MPD_POS|MPD_STATIC|MPD_CONST_DATA,
0, 19, 1, 1, inv10_p_data};
#elif defined(CONFIG_32) && _PyHASH_BITS == 31
@@ -4934,7 +4934,7 @@
PyObject *result;

CONVERT_OP_RAISE(&result, v, context);
- return result;
+ return result;
}

static PyObject *
diff --git a/Modules/_decimal/tests/deccheck.py b/Modules/_decimal/tests/deccheck.py
--- a/Modules/_decimal/tests/deccheck.py
+++ b/Modules/_decimal/tests/deccheck.py
@@ -302,6 +302,7 @@
dec = maxcontext.create_decimal(value)
if maxcontext.flags[P.Inexact] or \
maxcontext.flags[P.Rounded] or \
+ maxcontext.flags[P.Clamped] or \
maxcontext.flags[P.InvalidOperation]:
return context.p._raise_error(P.InvalidOperation)
if maxcontext.flags[P.FloatOperation]:
diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c
--- a/Modules/_elementtree.c
+++ b/Modules/_elementtree.c
@@ -48,6 +48,7 @@
/* See http://www.python.org/psf/license for licensing details. */

#include "Python.h"
+#include "structmember.h"

#define VERSION "1.0.6"

@@ -229,6 +230,8 @@

ElementObjectExtra* extra;

+ PyObject *weakreflist; /* For tp_weaklistoffset */
+
} ElementObject;

static PyTypeObject Element_Type;
@@ -261,17 +264,26 @@
LOCAL(void)
dealloc_extra(ElementObject* self)
{
+ ElementObjectExtra *myextra;
int i;

- Py_DECREF(self->extra->attrib);
-
- for (i = 0; i < self->extra->length; i++)
- Py_DECREF(self->extra->children[i]);
-
- if (self->extra->children != self->extra->_children)
- PyObject_Free(self->extra->children);
-
- PyObject_Free(self->extra);
+ if (!self->extra)
+ return;
+
+ /* Avoid DECREFs calling into this code again (cycles, etc.)
+ */
+ myextra = self->extra;
+ self->extra = NULL;
+
+ Py_DECREF(myextra->attrib);
+
+ for (i = 0; i < myextra->length; i++)
+ Py_DECREF(myextra->children[i]);
+
+ if (myextra->children != myextra->_children)
+ PyObject_Free(myextra->children);
+
+ PyObject_Free(myextra);
}

/* Convenience internal function to create new Element objects with the given
@@ -308,6 +320,8 @@
Py_INCREF(Py_None);
self->tail = Py_None;

+ self->weakreflist = NULL;
+
ALLOC(sizeof(ElementObject), "create element");
PyObject_GC_Track(self);
return (PyObject*) self;
@@ -328,6 +342,7 @@
e->tail = Py_None;

e->extra = NULL;
+ e->weakreflist = NULL;
}
return (PyObject *)e;
}
@@ -576,19 +591,28 @@
static int
element_gc_clear(ElementObject *self)
{
- PyObject *text = JOIN_OBJ(self->text);
- PyObject *tail = JOIN_OBJ(self->tail);
Py_CLEAR(self->tag);
- Py_CLEAR(text);
- Py_CLEAR(tail);
+
+ /* The following is like Py_CLEAR for self->text and self->tail, but
+ * written explicitily because the real pointers hide behind access
+ * macros.
+ */
+ if (self->text) {
+ PyObject *tmp = JOIN_OBJ(self->text);
+ self->text = NULL;
+ Py_DECREF(tmp);
+ }
+
+ if (self->tail) {
+ PyObject *tmp = JOIN_OBJ(self->tail);
+ self->tail = NULL;
+ Py_DECREF(tmp);
+ }

/* After dropping all references from extra, it's no longer valid anyway,
- ** so fully deallocate it (see also element_clearmethod)
+ * so fully deallocate it.
*/
- if (self->extra) {
- dealloc_extra(self);
- self->extra = NULL;
- }
+ dealloc_extra(self);
return 0;
}

@@ -596,6 +620,10 @@
element_dealloc(ElementObject* self)
{
PyObject_GC_UnTrack(self);
+
+ if (self->weakreflist != NULL)
+ PyObject_ClearWeakRefs((PyObject *) self);
+
/* element_gc_clear clears all references and deallocates extra
*/
element_gc_clear(self);
@@ -626,10 +654,7 @@
if (!PyArg_ParseTuple(args, ":clear"))
return NULL;

- if (self->extra) {
- dealloc_extra(self);
- self->extra = NULL;
- }
+ dealloc_extra(self);

Py_INCREF(Py_None);
Py_DECREF(JOIN_OBJ(self->text));
@@ -1693,7 +1718,7 @@
(traverseproc)element_gc_traverse, /* tp_traverse */
(inquiry)element_gc_clear, /* tp_clear */
0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
+ offsetof(ElementObject, weakreflist), /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
element_methods, /* tp_methods */
@@ -3009,8 +3034,7 @@
PyMODINIT_FUNC
PyInit__elementtree(void)
{
- PyObject* m;
- PyObject* g;
+ PyObject *m, *g, *temp;
char* bootstrap;

/* Initialize object types */
@@ -3042,10 +3066,6 @@
PyDict_SetItemString(g, "__builtins__", PyEval_GetBuiltins());

bootstrap = (
-
- "from copy import deepcopy\n"
- "from xml.etree import ElementPath\n"
-
"def iter(node, tag=None):\n" /* helper */
" if tag == '*':\n"
" tag = None\n"
@@ -3069,8 +3089,14 @@
if (!PyRun_String(bootstrap, Py_file_input, g, NULL))
return NULL;

- elementpath_obj = PyDict_GetItemString(g, "ElementPath");
- elementtree_deepcopy_obj = PyDict_GetItemString(g, "deepcopy");
+ if (!(temp = PyImport_ImportModule("copy")))
+ return NULL;
+ elementtree_deepcopy_obj = PyObject_GetAttrString(temp, "deepcopy");
+ Py_XDECREF(temp);
+
+ if (!(elementpath_obj = PyImport_ImportModule("xml.etree.ElementPath")))
+ return NULL;
+
elementtree_iter_obj = PyDict_GetItemString(g, "iter");
elementtree_itertext_obj = PyDict_GetItemString(g, "itertext");

diff --git a/Modules/arraymodule.c b/Modules/arraymodule.c
--- a/Modules/arraymodule.c
+++ b/Modules/arraymodule.c
@@ -2753,6 +2753,34 @@
return 0;
}

+static PyObject *
+arrayiter_reduce(arrayiterobject *it)
+{
+ return Py_BuildValue("N(O)n", _PyObject_GetBuiltin("iter"),
+ it->ao, it->index);
+}
+
+static PyObject *
+arrayiter_setstate(arrayiterobject *it, PyObject *state)
+{
+ Py_ssize_t index = PyLong_AsSsize_t(state);
+ if (index == -1 && PyErr_Occurred())
+ return NULL;
+ if (index < 0)
+ index = 0;
+ it->index = index;
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(setstate_doc, "Set state information for unpickling.");
+static PyMethodDef arrayiter_methods[] = {
+ {"__reduce__", (PyCFunction)arrayiter_reduce, METH_NOARGS,
+ reduce_doc},
+ {"__setstate__", (PyCFunction)arrayiter_setstate, METH_O,
+ setstate_doc},
+ {NULL, NULL} /* sentinel */
+};
+
static PyTypeObject PyArrayIter_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
"arrayiterator", /* tp_name */
@@ -2782,7 +2810,7 @@
0, /* tp_weaklistoffset */
PyObject_SelfIter, /* tp_iter */
(iternextfunc)arrayiter_next, /* tp_iternext */
- 0, /* tp_methods */
+ arrayiter_methods, /* tp_methods */
};


diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c
--- a/Modules/itertoolsmodule.c
+++ b/Modules/itertoolsmodule.c
@@ -134,6 +134,53 @@
return r;
}

+static PyObject *
+groupby_reduce(groupbyobject *lz)
+{
+ /* reduce as a 'new' call with an optional 'setstate' if groupby
+ * has started
+ */
+ PyObject *value;
+ if (lz->tgtkey && lz->currkey && lz->currvalue)
+ value = Py_BuildValue("O(OO)(OOO)", Py_TYPE(lz),
+ lz->it, lz->keyfunc, lz->currkey, lz->currvalue, lz->tgtkey);
+ else
+ value = Py_BuildValue("O(OO)", Py_TYPE(lz),
+ lz->it, lz->keyfunc);
+
+ return value;
+}
+
+PyDoc_STRVAR(reduce_doc, "Return state information for pickling.");
+
+static PyObject *
+groupby_setstate(groupbyobject *lz, PyObject *state)
+{
+ PyObject *currkey, *currvalue, *tgtkey;
+ if (!PyArg_ParseTuple(state, "OOO", &currkey, &currvalue, &tgtkey))
+ return NULL;
+ Py_CLEAR(lz->currkey);
+ lz->currkey = currkey;
+ Py_INCREF(lz->currkey);
+ Py_CLEAR(lz->currvalue);
+ lz->currvalue = currvalue;
+ Py_INCREF(lz->currvalue);
+ Py_CLEAR(lz->tgtkey);
+ lz->tgtkey = tgtkey;
+ Py_INCREF(lz->tgtkey);
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(setstate_doc, "Set state information for unpickling.");
+
+static PyMethodDef groupby_methods[] = {
+ {"__reduce__", (PyCFunction)groupby_reduce, METH_NOARGS,
+ reduce_doc},
+ {"__setstate__", (PyCFunction)groupby_setstate, METH_O,
+ setstate_doc},
+ {NULL, NULL} /* sentinel */
+};
+
PyDoc_STRVAR(groupby_doc,
"groupby(iterable[, keyfunc]) -> create an iterator which returns\n\
(key, sub-iterator) grouped by each value of key(value).\n");
@@ -168,7 +215,7 @@
0, /* tp_weaklistoffset */
PyObject_SelfIter, /* tp_iter */
(iternextfunc)groupby_next, /* tp_iternext */
- 0, /* tp_methods */
+ groupby_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
@@ -194,6 +241,17 @@
static PyTypeObject _grouper_type;

static PyObject *
+_grouper_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ PyObject *parent, *tgtkey;
+
+ if (!PyArg_ParseTuple(args, "O!O", &groupby_type, &parent, &tgtkey))
+ return NULL;
+
+ return _grouper_create((groupbyobject*) parent, tgtkey);
+}
+
+static PyObject *
_grouper_create(groupbyobject *parent, PyObject *tgtkey)
{
_grouperobject *igo;
@@ -269,6 +327,20 @@
return r;
}

+static PyObject *
+_grouper_reduce(_grouperobject *lz)
+{
+ return Py_BuildValue("O(OO)", Py_TYPE(lz),
+ lz->parent, lz->tgtkey);
+}
+
+static PyMethodDef _grouper_methods[] = {
+ {"__reduce__", (PyCFunction)_grouper_reduce, METH_NOARGS,
+ reduce_doc},
+ {NULL, NULL} /* sentinel */
+};
+
+
static PyTypeObject _grouper_type = {
PyVarObject_HEAD_INIT(NULL, 0)
"itertools._grouper", /* tp_name */
@@ -298,7 +370,7 @@
0, /* tp_weaklistoffset */
PyObject_SelfIter, /* tp_iter */
(iternextfunc)_grouper_next, /* tp_iternext */
- 0, /* tp_methods */
+ _grouper_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
@@ -308,7 +380,7 @@
0, /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
- 0, /* tp_new */
+ _grouper_new, /* tp_new */
PyObject_GC_Del, /* tp_free */
};

@@ -344,7 +416,7 @@
static PyTypeObject teedataobject_type;

static PyObject *
-teedataobject_new(PyObject *it)
+teedataobject_newinternal(PyObject *it)
{
teedataobject *tdo;

@@ -364,7 +436,7 @@
teedataobject_jumplink(teedataobject *tdo)
{
if (tdo->nextlink == NULL)
- tdo->nextlink = teedataobject_new(tdo->it);
+ tdo->nextlink = teedataobject_newinternal(tdo->it);
Py_XINCREF(tdo->nextlink);
return tdo->nextlink;
}
@@ -420,11 +492,80 @@
PyObject_GC_Del(tdo);
}

+static PyObject *
+teedataobject_reduce(teedataobject *tdo)
+{
+ int i;
+ /* create a temporary list of already iterated values */
+ PyObject *values = PyList_New(tdo->numread);
+ if (!values)
+ return NULL;
+ for (i=0 ; i<tdo->numread ; i++) {
+ Py_INCREF(tdo->values[i]);
+ PyList_SET_ITEM(values, i, tdo->values[i]);
+ }
+ return Py_BuildValue("O(ONO)", Py_TYPE(tdo), tdo->it,
+ values,
+ tdo->nextlink ? tdo->nextlink : Py_None);
+}
+
+static PyTypeObject teedataobject_type;
+
+static PyObject *
+teedataobject_new(PyTypeObject *type, PyObject *args, PyObject *kw)
+{
+ teedataobject *tdo;
+ PyObject *it, *values, *next;
+ Py_ssize_t i, len;
+
+ assert(type == &teedataobject_type);
+ if (!PyArg_ParseTuple(args, "OO!O", &it, &PyList_Type, &values, &next))
+ return NULL;
+
+ tdo = (teedataobject *)teedataobject_newinternal(it);
+ if (!tdo)
+ return NULL;
+
+ len = PyList_GET_SIZE(values);
+ if (len > LINKCELLS)
+ goto err;
+ for (i=0; i<len; i++) {
+ tdo->values[i] = PyList_GET_ITEM(values, i);
+ Py_INCREF(tdo->values[i]);
+ }
+ tdo->numread = len;
+
+ if (len == LINKCELLS) {
+ if (next != Py_None) {
+ if (Py_TYPE(next) != &teedataobject_type)
+ goto err;
+ assert(tdo->nextlink == NULL);
+ Py_INCREF(next);
+ tdo->nextlink = next;
+ }
+ } else {
+ if (next != Py_None)
+ goto err; /* shouldn't have a next if we are not full */
+ }
+ return (PyObject*)tdo;
+
+err:
+ Py_XDECREF(tdo);
+ PyErr_SetString(PyExc_ValueError, "Invalid arguments");
+ return NULL;
+}
+
+static PyMethodDef teedataobject_methods[] = {
+ {"__reduce__", (PyCFunction)teedataobject_reduce, METH_NOARGS,
+ reduce_doc},
+ {NULL, NULL} /* sentinel */
+};
+
PyDoc_STRVAR(teedataobject_doc, "Data container common to multiple tee objects.");

static PyTypeObject teedataobject_type = {
PyVarObject_HEAD_INIT(0, 0) /* Must fill in type value later */
- "itertools.tee_dataobject", /* tp_name */
+ "itertools._tee_dataobject", /* tp_name */
sizeof(teedataobject), /* tp_basicsize */
0, /* tp_itemsize */
/* methods */
@@ -451,7 +592,7 @@
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
- 0, /* tp_methods */
+ teedataobject_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
@@ -461,7 +602,7 @@
0, /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
- 0, /* tp_new */
+ teedataobject_new, /* tp_new */
PyObject_GC_Del, /* tp_free */
};

@@ -528,7 +669,7 @@
to = PyObject_GC_New(teeobject, &tee_type);
if (to == NULL)
goto done;
- to->dataobj = (teedataobject *)teedataobject_new(it);
+ to->dataobj = (teedataobject *)teedataobject_newinternal(it);
if (!to->dataobj) {
PyObject_GC_Del(to);
to = NULL;
@@ -548,7 +689,7 @@
{
PyObject *iterable;

- if (!PyArg_UnpackTuple(args, "tee", 1, 1, &iterable))
+ if (!PyArg_UnpackTuple(args, "_tee", 1, 1, &iterable))
return NULL;
return tee_fromiterable(iterable);
}
@@ -570,17 +711,43 @@
PyObject_GC_Del(to);
}

+static PyObject *
+tee_reduce(teeobject *to)
+{
+ return Py_BuildValue("O(())(Oi)", Py_TYPE(to), to->dataobj, to->index);
+}
+
+static PyObject *
+tee_setstate(teeobject *to, PyObject *state)
+{
+ teedataobject *tdo;
+ int index;
+ if (!PyArg_ParseTuple(state, "O!i", &teedataobject_type, &tdo, &index))
+ return NULL;
+ if (index < 0 || index > LINKCELLS) {
+ PyErr_SetString(PyExc_ValueError, "Index out of range");
+ return NULL;
+ }
+ Py_CLEAR(to->dataobj);
+ to->dataobj = tdo;
+ Py_INCREF(to->dataobj);
+ to->index = index;
+ Py_RETURN_NONE;
+}
+
PyDoc_STRVAR(teeobject_doc,
"Iterator wrapped to make it copyable");

static PyMethodDef tee_methods[] = {
{"__copy__", (PyCFunction)tee_copy, METH_NOARGS, teecopy_doc},
+ {"__reduce__", (PyCFunction)tee_reduce, METH_NOARGS, reduce_doc},
+ {"__setstate__", (PyCFunction)tee_setstate, METH_O, setstate_doc},
{NULL, NULL} /* sentinel */
};

static PyTypeObject tee_type = {
PyVarObject_HEAD_INIT(NULL, 0)
- "itertools.tee", /* tp_name */
+ "itertools._tee", /* tp_name */
sizeof(teeobject), /* tp_basicsize */
0, /* tp_itemsize */
/* methods */
@@ -771,6 +938,38 @@
}
}

+static PyObject *
+cycle_reduce(cycleobject *lz)
+{
+ /* Create a new cycle with the iterator tuple, then set
+ * the saved state on it.
+ */
+ return Py_BuildValue("O(O)(Oi)", Py_TYPE(lz),
+ lz->it, lz->saved, lz->firstpass);
+ }
+
+static PyObject *
+cycle_setstate(cycleobject *lz, PyObject *state)
+{
+ PyObject *saved=NULL;
+ int firstpass;
+ if (!PyArg_ParseTuple(state, "Oi", &saved, &firstpass))
+ return NULL;
+ Py_CLEAR(lz->saved);
+ lz->saved = saved;
+ Py_XINCREF(lz->saved);
+ lz->firstpass = firstpass != 0;
+ Py_RETURN_NONE;
+}
+
+static PyMethodDef cycle_methods[] = {
+ {"__reduce__", (PyCFunction)cycle_reduce, METH_NOARGS,
+ reduce_doc},
+ {"__setstate__", (PyCFunction)cycle_setstate, METH_O,
+ setstate_doc},
+ {NULL, NULL} /* sentinel */
+};
+
PyDoc_STRVAR(cycle_doc,
"cycle(iterable) --> cycle object\n\
\n\
@@ -807,7 +1006,7 @@
0, /* tp_weaklistoffset */
PyObject_SelfIter, /* tp_iter */
(iternextfunc)cycle_next, /* tp_iternext */
- 0, /* tp_methods */
+ cycle_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
@@ -913,6 +1112,31 @@
}
}

+static PyObject *
+dropwhile_reduce(dropwhileobject *lz)
+{
+ return Py_BuildValue("O(OO)l", Py_TYPE(lz),
+ lz->func, lz->it, lz->start);
+}
+
+static PyObject *
+dropwhile_setstate(dropwhileobject *lz, PyObject *state)
+{
+ int start = PyObject_IsTrue(state);
+ if (start == -1)
+ return NULL;
+ lz->start = start;
+ Py_RETURN_NONE;
+}
+
+static PyMethodDef dropwhile_methods[] = {
+ {"__reduce__", (PyCFunction)dropwhile_reduce, METH_NOARGS,
+ reduce_doc},
+ {"__setstate__", (PyCFunction)dropwhile_setstate, METH_O,
+ setstate_doc},
+ {NULL, NULL} /* sentinel */
+};
+
PyDoc_STRVAR(dropwhile_doc,
"dropwhile(predicate, iterable) --> dropwhile object\n\
\n\
@@ -949,7 +1173,7 @@
0, /* tp_weaklistoffset */
PyObject_SelfIter, /* tp_iter */
(iternextfunc)dropwhile_next, /* tp_iternext */
- 0, /* tp_methods */
+ dropwhile_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
@@ -1052,6 +1276,30 @@
return NULL;
}

+static PyObject *
+takewhile_reduce(takewhileobject *lz)
+{
+ return Py_BuildValue("O(OO)l", Py_TYPE(lz),
+ lz->func, lz->it, lz->stop);
+}
+
+static PyObject *
+takewhile_reduce_setstate(takewhileobject *lz, PyObject *state)
+{
+ int stop = PyObject_IsTrue(state);
+ if (stop == -1)
+ return NULL;
+ lz->stop = stop;
+ Py_RETURN_NONE;
+}
+
+static PyMethodDef takewhile_reduce_methods[] = {
+ {"__reduce__", (PyCFunction)takewhile_reduce, METH_NOARGS,
+ reduce_doc},
+ {"__setstate__", (PyCFunction)takewhile_reduce_setstate, METH_O,
+ setstate_doc},
+ {NULL, NULL} /* sentinel */
+};
PyDoc_STRVAR(takewhile_doc,
"takewhile(predicate, iterable) --> takewhile object\n\
\n\
@@ -1088,7 +1336,7 @@
0, /* tp_weaklistoffset */
PyObject_SelfIter, /* tp_iter */
(iternextfunc)takewhile_next, /* tp_iternext */
- 0, /* tp_methods */
+ takewhile_reduce_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
@@ -1244,6 +1492,44 @@
return item;
}

+static PyObject *
+islice_reduce(isliceobject *lz)
+{
+ /* When unpickled, generate a new object with the same bounds,
+ * then 'setstate' with the next and count
+ */
+ PyObject *stop;
+ if (lz->stop == -1) {
+ stop = Py_None;
+ Py_INCREF(stop);
+ } else {
+ stop = PyLong_FromSsize_t(lz->stop);
+ if (stop == NULL)
+ return NULL;
+ }
+ return Py_BuildValue("O(OnNn)n", Py_TYPE(lz),
+ lz->it, lz->next, stop, lz->step,
+ lz->cnt);
+}
+
+static PyObject *
+islice_setstate(isliceobject *lz, PyObject *state)
+{
+ Py_ssize_t cnt = PyLong_AsSsize_t(state);
+ if (cnt == -1 && PyErr_Occurred())
+ return NULL;
+ lz->cnt = cnt;
+ Py_RETURN_NONE;
+}
+
+static PyMethodDef islice_methods[] = {
+ {"__reduce__", (PyCFunction)islice_reduce, METH_NOARGS,
+ reduce_doc},
+ {"__setstate__", (PyCFunction)islice_setstate, METH_O,
+ setstate_doc},
+ {NULL, NULL} /* sentinel */
+};
+
PyDoc_STRVAR(islice_doc,
"islice(iterable, [start,] stop [, step]) --> islice object\n\
\n\
@@ -1284,7 +1570,7 @@
0, /* tp_weaklistoffset */
PyObject_SelfIter, /* tp_iter */
(iternextfunc)islice_next, /* tp_iternext */
- 0, /* tp_methods */
+ islice_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
@@ -1379,6 +1665,19 @@
return result;
}

+static PyObject *
+starmap_reduce(starmapobject *lz)
+{
+ /* Just pickle the iterator */
+ return Py_BuildValue("O(OO)", Py_TYPE(lz), lz->func, lz->it);
+}
+
+static PyMethodDef starmap_methods[] = {
+ {"__reduce__", (PyCFunction)starmap_reduce, METH_NOARGS,
+ reduce_doc},
+ {NULL, NULL} /* sentinel */
+};
+
PyDoc_STRVAR(starmap_doc,
"starmap(function, sequence) --> starmap object\n\
\n\
@@ -1415,7 +1714,7 @@
0, /* tp_weaklistoffset */
PyObject_SelfIter, /* tp_iter */
(iternextfunc)starmap_next, /* tp_iternext */
- 0, /* tp_methods */
+ starmap_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
@@ -1534,6 +1833,41 @@
return chain_next(lz); /* recurse and use next active */
}

+static PyObject *
+chain_reduce(chainobject *lz)
+{
+ if (lz->source) {
+ /* we can't pickle function objects (itertools.from_iterable) so
+ * we must use setstate to replace the iterable. One day we
+ * will fix pickling of functions
+ */
+ if (lz->active) {
+ return Py_BuildValue("O()(OO)", Py_TYPE(lz), lz->source, lz->active);
+ } else {
+ return Py_BuildValue("O()(O)", Py_TYPE(lz), lz->source);
+ }
+ } else {
+ return Py_BuildValue("O()", Py_TYPE(lz)); /* exhausted */
+ }
+ return NULL;
+}
+
+static PyObject *
+chain_setstate(chainobject *lz, PyObject *state)
+{
+ PyObject *source, *active=NULL;
+ if (! PyArg_ParseTuple(state, "O|O", &source, &active))
+ return NULL;
+
+ Py_CLEAR(lz->source);
+ lz->source = source;
+ Py_INCREF(lz->source);
+ Py_CLEAR(lz->active);
+ lz->active = active;
+ Py_XINCREF(lz->active);
+ Py_RETURN_NONE;
+}
+
PyDoc_STRVAR(chain_doc,
"chain(*iterables) --> chain object\n\
\n\
@@ -1550,6 +1884,10 @@
static PyMethodDef chain_methods[] = {
{"from_iterable", (PyCFunction) chain_new_from_iterable, METH_O | METH_CLASS,
chain_from_iterable_doc},
+ {"__reduce__", (PyCFunction)chain_reduce, METH_NOARGS,
+ reduce_doc},
+ {"__setstate__", (PyCFunction)chain_setstate, METH_O,
+ setstate_doc},
{NULL, NULL} /* sentinel */
};

@@ -1790,6 +2128,83 @@
return NULL;
}

+static PyObject *
+product_reduce(productobject *lz)
+{
+ if (lz->stopped) {
+ return Py_BuildValue("O(())", Py_TYPE(lz));
+ } else if (lz->result == NULL) {
+ return Py_BuildValue("OO", Py_TYPE(lz), lz->pools);
+ } else {
+ PyObject *indices;
+ Py_ssize_t n, i;
+
+ /* we must pickle the indices use them for setstate, and
+ * additionally indicate that the iterator has started
+ */
+ n = PyTuple_GET_SIZE(lz->pools);
+ indices = PyTuple_New(n);
+ if (indices == NULL)
+ return NULL;
+ for (i=0; i<n; i++){
+ PyObject* index = PyLong_FromSsize_t(lz->indices[i]);
+ if (!index) {
+ Py_DECREF(indices);
+ return NULL;
+ }
+ PyTuple_SET_ITEM(indices, i, index);
+ }
+ return Py_BuildValue("OON", Py_TYPE(lz), lz->pools, indices);
+ }
+}
+
+static PyObject *
+product_setstate(productobject *lz, PyObject *state)
+{
+ PyObject *result;
+ Py_ssize_t n, i;
+
+ n = PyTuple_GET_SIZE(lz->pools);
+ if (!PyTuple_Check(state) || PyTuple_GET_SIZE(state) != n) {
+ PyErr_SetString(PyExc_ValueError, "invalid arguments");
+ return NULL;
+ }
+ for (i=0; i<n; i++)
+ {
+ PyObject* indexObject = PyTuple_GET_ITEM(state, i);
+ Py_ssize_t index = PyLong_AsSsize_t(indexObject);
+ if (index < 0 && PyErr_Occurred())
+ return NULL; /* not an integer */
+ /* clamp the index */
+ if (index < 0)
+ index = 0;
+ else if (index > n-1)
+ index = n-1;
+ lz->indices[i] = index;
+ }
+
+ result = PyTuple_New(n);
+ if (!result)
+ return NULL;
+ for (i=0; i<n; i++) {
+ PyObject *pool = PyTuple_GET_ITEM(lz->pools, i);
+ PyObject *element = PyTuple_GET_ITEM(pool, lz->indices[i]);
+ Py_INCREF(element);
+ PyTuple_SET_ITEM(result, i, element);
+ }
+ Py_CLEAR(lz->result);
+ lz->result = result;
+ Py_RETURN_NONE;
+}
+
+static PyMethodDef product_methods[] = {
+ {"__reduce__", (PyCFunction)product_reduce, METH_NOARGS,
+ reduce_doc},
+ {"__setstate__", (PyCFunction)product_setstate, METH_O,
+ setstate_doc},
+ {NULL, NULL} /* sentinel */
+};
+
PyDoc_STRVAR(product_doc,
"product(*iterables) --> product object\n\
\n\
@@ -1834,7 +2249,7 @@
0, /* tp_weaklistoffset */
PyObject_SelfIter, /* tp_iter */
(iternextfunc)product_next, /* tp_iternext */
- 0, /* tp_methods */
+ product_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
@@ -2021,6 +2436,86 @@
return NULL;
}

+static PyObject *
+combinations_reduce(combinationsobject *lz)
+{
+ if (lz->result == NULL) {
+ return Py_BuildValue("O(On)", Py_TYPE(lz), lz->pool, lz->r);
+ } else if (lz->stopped) {
+ return Py_BuildValue("O(()n)", Py_TYPE(lz), lz->r);
+ } else {
+ PyObject *indices;
+ Py_ssize_t i;
+
+ /* we must pickle the indices and use them for setstate */
+ indices = PyTuple_New(lz->r);
+ if (!indices)
+ return NULL;
+ for (i=0; i<lz->r; i++)
+ {
+ PyObject* index = PyLong_FromSsize_t(lz->indices[i]);
+ if (!index) {
+ Py_DECREF(indices);
+ return NULL;
+ }
+ PyTuple_SET_ITEM(indices, i, index);
+ }
+
+ return Py_BuildValue("O(On)N", Py_TYPE(lz), lz->pool, lz->r, indices);
+ }
+}
+
+static PyObject *
+combinations_setstate(combinationsobject *lz, PyObject *state)
+{
+ PyObject *result;
+ Py_ssize_t i;
+ Py_ssize_t n = PyTuple_GET_SIZE(lz->pool);
+
+ if (!PyTuple_Check(state) || PyTuple_GET_SIZE(state) != lz->r)
+ {
+ PyErr_SetString(PyExc_ValueError, "invalid arguments");
+ return NULL;
+ }
+
+ for (i=0; i<lz->r; i++)
+ {
+ Py_ssize_t max;
+ PyObject* indexObject = PyTuple_GET_ITEM(state, i);
+ Py_ssize_t index = PyLong_AsSsize_t(indexObject);
+ if (index == -1 && PyErr_Occurred())
+ return NULL; /* not an integer */
+ max = i + n - lz->r;
+ /* clamp the index (beware of negative max) */
+ if (index > max)
+ index = max;
+ if (index < 0)
+ index = 0;
+ lz->indices[i] = index;
+ }
+
+ result = PyTuple_New(lz->r);
+ if (result == NULL)
+ return NULL;
+ for (i=0; i<lz->r; i++) {
+ PyObject *element = PyTuple_GET_ITEM(lz->pool, lz->indices[i]);
+ Py_INCREF(element);
+ PyTuple_SET_ITEM(result, i, element);
+ }
+
+ Py_CLEAR(lz->result);
+ lz->result = result;
+ Py_RETURN_NONE;
+}
+
+static PyMethodDef combinations_methods[] = {
+ {"__reduce__", (PyCFunction)combinations_reduce, METH_NOARGS,
+ reduce_doc},
+ {"__setstate__", (PyCFunction)combinations_setstate, METH_O,
+ setstate_doc},
+ {NULL, NULL} /* sentinel */
+};
+
PyDoc_STRVAR(combinations_doc,
"combinations(iterable, r) --> combinations object\n\
\n\
@@ -2029,11 +2524,11 @@

static PyTypeObject combinations_type = {
PyVarObject_HEAD_INIT(NULL, 0)
- "itertools.combinations", /* tp_name */
+ "itertools.combinations", /* tp_name */
sizeof(combinationsobject), /* tp_basicsize */
0, /* tp_itemsize */
/* methods */
- (destructor)combinations_dealloc, /* tp_dealloc */
+ (destructor)combinations_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
@@ -2050,14 +2545,14 @@
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
Py_TPFLAGS_BASETYPE, /* tp_flags */
- combinations_doc, /* tp_doc */
- (traverseproc)combinations_traverse, /* tp_traverse */
+ combinations_doc, /* tp_doc */
+ (traverseproc)combinations_traverse,/* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
PyObject_SelfIter, /* tp_iter */
- (iternextfunc)combinations_next, /* tp_iternext */
- 0, /* tp_methods */
+ (iternextfunc)combinations_next, /* tp_iternext */
+ combinations_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
@@ -2067,7 +2562,7 @@
0, /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
- combinations_new, /* tp_new */
+ combinations_new, /* tp_new */
PyObject_GC_Del, /* tp_free */
};

@@ -2266,6 +2761,82 @@
return NULL;
}

+static PyObject *
+cwr_reduce(cwrobject *lz)
+{
+ if (lz->result == NULL) {
+ return Py_BuildValue("O(On)", Py_TYPE(lz), lz->pool, lz->r);
+ } else if (lz->stopped) {
+ return Py_BuildValue("O(()n)", Py_TYPE(lz), lz->r);
+ } else {
+ PyObject *indices;
+ Py_ssize_t i;
+
+ /* we must pickle the indices and use them for setstate */
+ indices = PyTuple_New(lz->r);
+ if (!indices)
+ return NULL;
+ for (i=0; i<lz->r; i++)
+ {
+ PyObject* index = PyLong_FromSsize_t(lz->indices[i]);
+ if (!index) {
+ Py_DECREF(indices);
+ return NULL;
+ }
+ PyTuple_SET_ITEM(indices, i, index);
+ }
+
+ return Py_BuildValue("O(On)N", Py_TYPE(lz), lz->pool, lz->r, indices);
+ }
+}
+
+static PyObject *
+cwr_setstate(cwrobject *lz, PyObject *state)
+{
+ PyObject *result;
+ Py_ssize_t n, i;
+
+ if (!PyTuple_Check(state) || PyTuple_GET_SIZE(state) != lz->r)
+ {
+ PyErr_SetString(PyExc_ValueError, "invalid arguments");
+ return NULL;
+ }
+
+ n = PyTuple_GET_SIZE(lz->pool);
+ for (i=0; i<lz->r; i++)
+ {
+ PyObject* indexObject = PyTuple_GET_ITEM(state, i);
+ Py_ssize_t index = PyLong_AsSsize_t(indexObject);
+ if (index < 0 && PyErr_Occurred())
+ return NULL; /* not an integer */
+ /* clamp the index */
+ if (index < 0)
+ index = 0;
+ else if (index > n-1)
+ index = n-1;
+ lz->indices[i] = index;
+ }
+ result = PyTuple_New(lz->r);
+ if (result == NULL)
+ return NULL;
+ for (i=0; i<lz->r; i++) {
+ PyObject *element = PyTuple_GET_ITEM(lz->pool, lz->indices[i]);
+ Py_INCREF(element);
+ PyTuple_SET_ITEM(result, i, element);
+ }
+ Py_CLEAR(lz->result);
+ lz->result = result;
+ Py_RETURN_NONE;
+}
+
+static PyMethodDef cwr_methods[] = {
+ {"__reduce__", (PyCFunction)cwr_reduce, METH_NOARGS,
+ reduce_doc},
+ {"__setstate__", (PyCFunction)cwr_setstate, METH_O,
+ setstate_doc},
+ {NULL, NULL} /* sentinel */
+};
+
PyDoc_STRVAR(cwr_doc,
"combinations_with_replacement(iterable, r) --> combinations_with_replacement object\n\
\n\
@@ -2275,11 +2846,11 @@

static PyTypeObject cwr_type = {
PyVarObject_HEAD_INIT(NULL, 0)
- "itertools.combinations_with_replacement", /* tp_name */
- sizeof(cwrobject), /* tp_basicsize */
+ "itertools.combinations_with_replacement", /* tp_name */
+ sizeof(cwrobject), /* tp_basicsize */
0, /* tp_itemsize */
/* methods */
- (destructor)cwr_dealloc, /* tp_dealloc */
+ (destructor)cwr_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
@@ -2291,19 +2862,19 @@
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
- PyObject_GenericGetAttr, /* tp_getattro */
+ PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
- Py_TPFLAGS_BASETYPE, /* tp_flags */
- cwr_doc, /* tp_doc */
- (traverseproc)cwr_traverse, /* tp_traverse */
+ Py_TPFLAGS_BASETYPE, /* tp_flags */
+ cwr_doc, /* tp_doc */
+ (traverseproc)cwr_traverse, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
- PyObject_SelfIter, /* tp_iter */
- (iternextfunc)cwr_next, /* tp_iternext */
- 0, /* tp_methods */
+ PyObject_SelfIter, /* tp_iter */
+ (iternextfunc)cwr_next, /* tp_iternext */
+ cwr_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
@@ -2313,8 +2884,8 @@
0, /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
- cwr_new, /* tp_new */
- PyObject_GC_Del, /* tp_free */
+ cwr_new, /* tp_new */
+ PyObject_GC_Del, /* tp_free */
};


@@ -2538,6 +3109,115 @@
return NULL;
}

+static PyObject *
+permutations_reduce(permutationsobject *po)
+{
+ if (po->result == NULL) {
+ return Py_BuildValue("O(On)", Py_TYPE(po), po->pool, po->r);
+ } else if (po->stopped) {
+ return Py_BuildValue("O(()n)", Py_TYPE(po), po->r);
+ } else {
+ PyObject *indices=NULL, *cycles=NULL;
+ Py_ssize_t n, i;
+
+ /* we must pickle the indices and cycles and use them for setstate */
+ n = PyTuple_GET_SIZE(po->pool);
+ indices = PyTuple_New(n);
+ if (indices == NULL)
+ goto err;
+ for (i=0; i<n; i++){
+ PyObject* index = PyLong_FromSsize_t(po->indices[i]);
+ if (!index)
+ goto err;
+ PyTuple_SET_ITEM(indices, i, index);
+ }
+
+ cycles = PyTuple_New(po->r);
+ if (cycles == NULL)
+ goto err;
+ for (i=0; i<po->r; i++)
+ {
+ PyObject* index = PyLong_FromSsize_t(po->cycles[i]);
+ if (!index)
+ goto err;
+ PyTuple_SET_ITEM(cycles, i, index);
+ }
+ return Py_BuildValue("O(On)(NN)", Py_TYPE(po),
+ po->pool, po->r,
+ indices, cycles);
+ err:
+ Py_XDECREF(indices);
+ Py_XDECREF(cycles);
+ return NULL;
+ }
+}
+
+static PyObject *
+permutations_setstate(permutationsobject *po, PyObject *state)
+{
+ PyObject *indices, *cycles, *result;
+ Py_ssize_t n, i;
+
+ if (!PyArg_ParseTuple(state, "O!O!",
+ &PyTuple_Type, &indices,
+ &PyTuple_Type, &cycles))
+ return NULL;
+
+ n = PyTuple_GET_SIZE(po->pool);
+ if (PyTuple_GET_SIZE(indices) != n ||
+ PyTuple_GET_SIZE(cycles) != po->r)
+ {
+ PyErr_SetString(PyExc_ValueError, "invalid arguments");
+ return NULL;
+ }
+
+ for (i=0; i<n; i++)
+ {
+ PyObject* indexObject = PyTuple_GET_ITEM(indices, i);
+ Py_ssize_t index = PyLong_AsSsize_t(indexObject);
+ if (index < 0 && PyErr_Occurred())
+ return NULL; /* not an integer */
+ /* clamp the index */
+ if (index < 0)
+ index = 0;
+ else if (index > n-1)
+ index = n-1;
+ po->indices[i] = index;
+ }
+
+ for (i=0; i<po->r; i++)
+ {
+ PyObject* indexObject = PyTuple_GET_ITEM(cycles, i);
+ Py_ssize_t index = PyLong_AsSsize_t(indexObject);
+ if (index < 0 && PyErr_Occurred())
+ return NULL; /* not an integer */
+ if (index < 1)
+ index = 1;
+ else if (index > n-i)
+ index = n-i;
+ po->cycles[i] = index;
+ }
+ result = PyTuple_New(po->r);
+ if (result == NULL)
+ return NULL;
+ for (i=0; i<po->r; i++) {
+ PyObject *element = PyTuple_GET_ITEM(po->pool, po->indices[i]);
+ Py_INCREF(element);
+ PyTuple_SET_ITEM(result, i, element);
+ }
+ Py_CLEAR(po->result);
+ po->result = result;
+ Py_RETURN_NONE;
+}
+
+static PyMethodDef permuations_methods[] = {
+ {"__reduce__", (PyCFunction)permutations_reduce, METH_NOARGS,
+ reduce_doc},
+ {"__setstate__", (PyCFunction)permutations_setstate, METH_O,
+ setstate_doc},
+ {NULL, NULL} /* sentinel */
+};
+
PyDoc_STRVAR(permutations_doc,
"permutations(iterable[, r]) --> permutations object\n\
\n\
@@ -2574,7 +3254,7 @@
0, /* tp_weaklistoffset */
PyObject_SelfIter, /* tp_iter */
(iternextfunc)permutations_next, /* tp_iternext */
- 0, /* tp_methods */
+ permuations_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
@@ -2605,7 +3285,7 @@
static char *kwargs[] = {"iterable", "func", NULL};
PyObject *iterable;
PyObject *it;
- PyObject *binop = NULL;
+ PyObject *binop = Py_None;
accumulateobject *lz;

if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:accumulate",
@@ -2624,8 +3304,10 @@
return NULL;
}

- Py_XINCREF(binop);
- lz->binop = binop;
+ if (binop != Py_None) {
+ Py_XINCREF(binop);
+ lz->binop = binop;
+ }
lz->total = NULL;
lz->it = it;
return (PyObject *)lz;
@@ -2681,6 +3363,31 @@
return newtotal;
}

+static PyObject *
+accumulate_reduce(accumulateobject *lz)
+{
+ return Py_BuildValue("O(OO)O", Py_TYPE(lz),
+ lz->it, lz->binop?lz->binop:Py_None,
+ lz->total?lz->total:Py_None);
+ }
+
+static PyObject *
+accumulate_setstate(accumulateobject *lz, PyObject *state)
+{
+ Py_CLEAR(lz->total);
+ lz->total = state;
+ Py_INCREF(lz->total);
+ Py_RETURN_NONE;
+}
+
+static PyMethodDef accumulate_methods[] = {
+ {"__reduce__", (PyCFunction)accumulate_reduce, METH_NOARGS,
+ reduce_doc},
+ {"__setstate__", (PyCFunction)accumulate_setstate, METH_O,
+ setstate_doc},
+ {NULL, NULL} /* sentinel */
+};
+
PyDoc_STRVAR(accumulate_doc,
"accumulate(iterable[, func]) --> accumulate object\n\
\n\
@@ -2716,7 +3423,7 @@
0, /* tp_weaklistoffset */
PyObject_SelfIter, /* tp_iter */
(iternextfunc)accumulate_next, /* tp_iternext */
- 0, /* tp_methods */
+ accumulate_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
@@ -2833,6 +3540,19 @@
}
}

+static PyObject *
+compress_reduce(compressobject *lz)
+{
+ return Py_BuildValue("O(OO)", Py_TYPE(lz),
+ lz->data, lz->selectors);
+ }
+
+static PyMethodDef compress_methods[] = {
+ {"__reduce__", (PyCFunction)compress_reduce, METH_NOARGS,
+ reduce_doc},
+ {NULL, NULL} /* sentinel */
+};
+
PyDoc_STRVAR(compress_doc,
"compress(data, selectors) --> iterator over selected data\n\
\n\
@@ -2870,7 +3590,7 @@
0, /* tp_weaklistoffset */
PyObject_SelfIter, /* tp_iter */
(iternextfunc)compress_next, /* tp_iternext */
- 0, /* tp_methods */
+ compress_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
@@ -2977,6 +3697,19 @@
}
}

+static PyObject *
+filterfalse_reduce(filterfalseobject *lz)
+{
+ return Py_BuildValue("O(OO)", Py_TYPE(lz),
+ lz->func, lz->it);
+ }
+
+static PyMethodDef filterfalse_methods[] = {
+ {"__reduce__", (PyCFunction)filterfalse_reduce, METH_NOARGS,
+ reduce_doc},
+ {NULL, NULL} /* sentinel */
+};
+
PyDoc_STRVAR(filterfalse_doc,
"filterfalse(function or None, sequence) --> filterfalse object\n\
\n\
@@ -3013,7 +3746,7 @@
0, /* tp_weaklistoffset */
PyObject_SelfIter, /* tp_iter */
(iternextfunc)filterfalse_next, /* tp_iternext */
- 0, /* tp_methods */
+ filterfalse_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
@@ -3207,11 +3940,9 @@
return Py_BuildValue("O(n)", Py_TYPE(lz), lz->cnt);
}

-PyDoc_STRVAR(count_reduce_doc, "Return state information for pickling.");
-
static PyMethodDef count_methods[] = {
{"__reduce__", (PyCFunction)count_reduce, METH_NOARGS,
- count_reduce_doc},
+ reduce_doc},
{NULL, NULL} /* sentinel */
};

@@ -3352,8 +4083,21 @@

PyDoc_STRVAR(length_hint_doc, "Private method returning an estimate of len(list(it)).");

+static PyObject *
+repeat_reduce(repeatobject *ro)
+{
+ /* unpickle this so that a new repeat iterator is constructed with an
+ * object, then call __setstate__ on it to set cnt
+ */
+ if (ro->cnt >= 0)
+ return Py_BuildValue("O(On)", Py_TYPE(ro), ro->element, ro->cnt);
+ else
+ return Py_BuildValue("O(O)", Py_TYPE(ro), ro->element);
+}
+
static PyMethodDef repeat_methods[] = {
{"__length_hint__", (PyCFunction)repeat_len, METH_NOARGS, length_hint_doc},
+ {"__reduce__", (PyCFunction)repeat_reduce, METH_NOARGS, reduce_doc},
{NULL, NULL} /* sentinel */
};

@@ -3579,6 +4323,49 @@
return result;
}

+static PyObject *
+zip_longest_reduce(ziplongestobject *lz)
+{
+
+ /* Create a new tuple with empty sequences where appropriate to pickle.
+ * Then use setstate to set the fillvalue
+ */
+ int i;
+ PyObject *args = PyTuple_New(PyTuple_GET_SIZE(lz->ittuple));
+ if (args == NULL)
+ return NULL;
+ for (i=0; i<PyTuple_GET_SIZE(lz->ittuple); i++) {
+ PyObject *elem = PyTuple_GET_ITEM(lz->ittuple, i);
+ if (elem == NULL) {
+ elem = PyTuple_New(0);
+ if (elem == NULL) {
+ Py_DECREF(args);
+ return NULL;
+ }
+ } else
+ Py_INCREF(elem);
+ PyTuple_SET_ITEM(args, i, elem);
+ }
+ return Py_BuildValue("ONO", Py_TYPE(lz), args, lz->fillvalue);
+}
+
+static PyObject *
+zip_longest_setstate(ziplongestobject *lz, PyObject *state)
+{
+ Py_CLEAR(lz->fillvalue);
+ lz->fillvalue = state;
+ Py_INCREF(lz->fillvalue);
+ Py_RETURN_NONE;
+}
+
+static PyMethodDef zip_longest_methods[] = {
+ {"__reduce__", (PyCFunction)zip_longest_reduce, METH_NOARGS,
+ reduce_doc},
+ {"__setstate__", (PyCFunction)zip_longest_setstate, METH_O,
+ setstate_doc},
+ {NULL, NULL} /* sentinel */
+};
+
PyDoc_STRVAR(zip_longest_doc,
"zip_longest(iter1 [,iter2 [...]], [fillvalue=None]) --> zip_longest object\n\
\n\
@@ -3620,7 +4407,7 @@
0, /* tp_weaklistoffset */
PyObject_SelfIter, /* tp_iter */
(iternextfunc)zip_longest_next, /* tp_iternext */
- 0, /* tp_methods */
+ zip_longest_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
@@ -3708,6 +4495,9 @@
&product_type,
&repeat_type,
&groupby_type,
+ &_grouper_type,
+ &tee_type,
+ &teedataobject_type,
NULL
};

@@ -3725,11 +4515,5 @@
PyModule_AddObject(m, name+1, (PyObject *)typelist[i]);
}

- if (PyType_Ready(&teedataobject_type) < 0)
- return NULL;
- if (PyType_Ready(&tee_type) < 0)
- return NULL;
- if (PyType_Ready(&_grouper_type) < 0)
- return NULL;
return m;
}
diff --git a/Objects/bytearrayobject.c b/Objects/bytearrayobject.c
--- a/Objects/bytearrayobject.c
+++ b/Objects/bytearrayobject.c
@@ -3003,7 +3003,7 @@
}

static PyObject *
-bytesarrayiter_length_hint(bytesiterobject *it)
+bytearrayiter_length_hint(bytesiterobject *it)
{
Py_ssize_t len = 0;
if (it->it_seq)
@@ -3014,9 +3014,41 @@
PyDoc_STRVAR(length_hint_doc,
"Private method returning an estimate of len(list(it)).");

+static PyObject *
+bytearrayiter_reduce(bytesiterobject *it)
+{
+ if (it->it_seq != NULL) {
+ return Py_BuildValue("N(O)n", _PyObject_GetBuiltin("iter"),
+ it->it_seq, it->it_index);
+ } else {
+ PyObject *u = PyUnicode_FromUnicode(NULL, 0);
+ if (u == NULL)
+ return NULL;
+ return Py_BuildValue("N(N)", _PyObject_GetBuiltin("iter"), u);
+ }
+}
+
+static PyObject *
+bytearrayiter_setstate(bytesiterobject *it, PyObject *state)
+{
+ Py_ssize_t index = PyLong_AsSsize_t(state);
+ if (index == -1 && PyErr_Occurred())
+ return NULL;
+ if (index < 0)
+ index = 0;
+ it->it_index = index;
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(setstate_doc, "Set state information for unpickling.");
+
static PyMethodDef bytearrayiter_methods[] = {
- {"__length_hint__", (PyCFunction)bytesarrayiter_length_hint, METH_NOARGS,
+ {"__length_hint__", (PyCFunction)bytearrayiter_length_hint, METH_NOARGS,
length_hint_doc},
+ {"__reduce__", (PyCFunction)bytearrayiter_reduce, METH_NOARGS,
+ reduce_doc},
+ {"__setstate__", (PyCFunction)bytearrayiter_setstate, METH_O,
+ setstate_doc},
{NULL, NULL} /* sentinel */
};

diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c
--- a/Objects/bytesobject.c
+++ b/Objects/bytesobject.c
@@ -3074,9 +3074,43 @@
PyDoc_STRVAR(length_hint_doc,
"Private method returning an estimate of len(list(it)).");

+static PyObject *
+striter_reduce(striterobject *it)
+{
+ if (it->it_seq != NULL) {
+ return Py_BuildValue("N(O)n", _PyObject_GetBuiltin("iter"),
+ it->it_seq, it->it_index);
+ } else {
+ PyObject *u = PyUnicode_FromUnicode(NULL, 0);
+ if (u == NULL)
+ return NULL;
+ return Py_BuildValue("N(N)", _PyObject_GetBuiltin("iter"), u);
+ }
+}
+
+PyDoc_STRVAR(reduce_doc, "Return state information for pickling.");
+
+static PyObject *
+striter_setstate(striterobject *it, PyObject *state)
+{
+ Py_ssize_t index = PyLong_AsSsize_t(state);
+ if (index == -1 && PyErr_Occurred())
+ return NULL;
+ if (index < 0)
+ index = 0;
+ it->it_index = index;
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(setstate_doc, "Set state information for unpickling.");
+
static PyMethodDef striter_methods[] = {
{"__length_hint__", (PyCFunction)striter_len, METH_NOARGS,
length_hint_doc},
+ {"__reduce__", (PyCFunction)striter_reduce, METH_NOARGS,
+ reduce_doc},
+ {"__setstate__", (PyCFunction)striter_setstate, METH_O,
+ setstate_doc},
{NULL, NULL} /* sentinel */
};

diff --git a/Objects/dictobject.c b/Objects/dictobject.c
--- a/Objects/dictobject.c
+++ b/Objects/dictobject.c
@@ -2323,9 +2323,16 @@
PyDoc_STRVAR(length_hint_doc,
"Private method returning an estimate of len(list(it)).");

+static PyObject *
+dictiter_reduce(dictiterobject *di);
+
+PyDoc_STRVAR(reduce_doc, "Return state information for pickling.");
+
static PyMethodDef dictiter_methods[] = {
{"__length_hint__", (PyCFunction)dictiter_len, METH_NOARGS,
length_hint_doc},
+ {"__reduce__", (PyCFunction)dictiter_reduce, METH_NOARGS,
+ reduce_doc},
{NULL, NULL} /* sentinel */
};

@@ -2560,6 +2567,52 @@
};


+static PyObject *
+dictiter_reduce(dictiterobject *di)
+{
+ PyObject *list;
+ dictiterobject tmp;
+
+ list = PyList_New(0);
+ if (!list)
+ return NULL;
+
+ /* copy the itertor state */
+ tmp = *di;
+ Py_XINCREF(tmp.di_dict);
+
+ /* iterate the temporary into a list */
+ for(;;) {
+ PyObject *element = 0;
+ if (Py_TYPE(di) == &PyDictIterItem_Type)
+ element = dictiter_iternextitem(&tmp);
+ else if (Py_TYPE(di) == &PyDictIterKey_Type)
+ element = dictiter_iternextkey(&tmp);
+ else if (Py_TYPE(di) == &PyDictIterValue_Type)
+ element = dictiter_iternextvalue(&tmp);
+ else
+ assert(0);
+ if (element) {
+ if (PyList_Append(list, element)) {
+ Py_DECREF(element);
+ Py_DECREF(list);
+ Py_XDECREF(tmp.di_dict);
+ return NULL;
+ }
+ Py_DECREF(element);
+ } else
+ break;
+ }
+ Py_XDECREF(tmp.di_dict);
+ /* check for error */
+ if (tmp.di_dict != NULL) {
+ /* we have an error */
+ Py_DECREF(list);
+ return NULL;
+ }
+ return Py_BuildValue("N(N)", _PyObject_GetBuiltin("iter"), list);
+}
+
/***********************************************/
/* View objects for keys(), items(), values(). */
/***********************************************/
diff --git a/Objects/enumobject.c b/Objects/enumobject.c
--- a/Objects/enumobject.c
+++ b/Objects/enumobject.c
@@ -158,6 +158,22 @@
return result;
}

+static PyObject *
+enum_reduce(enumobject *en)
+{
+ if (en->en_longindex != NULL)
+ return Py_BuildValue("O(OO)", Py_TYPE(en), en->en_sit, en->en_longindex);
+ else
+ return Py_BuildValue("O(On)", Py_TYPE(en), en->en_sit, en->en_index);
+}
+
+PyDoc_STRVAR(reduce_doc, "Return state information for pickling.");
+
+static PyMethodDef enum_methods[] = {
+ {"__reduce__", (PyCFunction)enum_reduce, METH_NOARGS, reduce_doc},
+ {NULL, NULL} /* sentinel */
+};
+
PyDoc_STRVAR(enum_doc,
"enumerate(iterable[, start]) -> iterator for index, value of iterable\n"
"\n"
@@ -197,7 +213,7 @@
0, /* tp_weaklistoffset */
PyObject_SelfIter, /* tp_iter */
(iternextfunc)enum_next, /* tp_iternext */
- 0, /* tp_methods */
+ enum_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
@@ -319,8 +335,40 @@

PyDoc_STRVAR(length_hint_doc, "Private method returning an estimate of len(list(it)).");

+static PyObject *
+reversed_reduce(reversedobject *ro)
+{
+ if (ro->seq)
+ return Py_BuildValue("O(O)n", Py_TYPE(ro), ro->seq, ro->index);
+ else
+ return Py_BuildValue("O(())", Py_TYPE(ro));
+}
+
+static PyObject *
+reversed_setstate(reversedobject *ro, PyObject *state)
+{
+ Py_ssize_t index = PyLong_AsSsize_t(state);
+ if (index == -1 && PyErr_Occurred())
+ return NULL;
+ if (ro->seq != 0) {
+ Py_ssize_t n = PySequence_Size(ro->seq);
+ if (n < 0)
+ return NULL;
+ if (index < -1)
+ index = -1;
+ else if (index > n-1)
+ index = n-1;
+ ro->index = index;
+ }
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(setstate_doc, "Set state information for unpickling.");
+
static PyMethodDef reversediter_methods[] = {
{"__length_hint__", (PyCFunction)reversed_len, METH_NOARGS, length_hint_doc},
+ {"__reduce__", (PyCFunction)reversed_reduce, METH_NOARGS, reduce_doc},
+ {"__setstate__", (PyCFunction)reversed_setstate, METH_O, setstate_doc},
{NULL, NULL} /* sentinel */
};

diff --git a/Objects/iterobject.c b/Objects/iterobject.c
--- a/Objects/iterobject.c
+++ b/Objects/iterobject.c
@@ -88,8 +88,38 @@

PyDoc_STRVAR(length_hint_doc, "Private method returning an estimate of len(list(it)).");

+static PyObject *
+iter_reduce(seqiterobject *it)
+{
+ if (it->it_seq != NULL)
+ return Py_BuildValue("N(O)n", _PyObject_GetBuiltin("iter"),
+ it->it_seq, it->it_index);
+ else
+ return Py_BuildValue("N(())", _PyObject_GetBuiltin("iter"));
+}
+
+PyDoc_STRVAR(reduce_doc, "Return state information for pickling.");
+
+static PyObject *
+iter_setstate(seqiterobject *it, PyObject *state)
+{
+ Py_ssize_t index = PyLong_AsSsize_t(state);
+ if (index == -1 && PyErr_Occurred())
+ return NULL;
+ if (it->it_seq != NULL) {
+ if (index < 0)
+ index = 0;
+ it->it_index = index;
+ }
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(setstate_doc, "Set state information for unpickling.");
+
static PyMethodDef seqiter_methods[] = {
{"__length_hint__", (PyCFunction)iter_len, METH_NOARGS, length_hint_doc},
+ {"__reduce__", (PyCFunction)iter_reduce, METH_NOARGS, reduce_doc},
+ {"__setstate__", (PyCFunction)iter_setstate, METH_O, setstate_doc},
{NULL, NULL} /* sentinel */
};

@@ -195,6 +225,21 @@
return NULL;
}

+static PyObject *
+calliter_reduce(calliterobject *it)
+{
+ if (it->it_callable != NULL && it->it_sentinel != NULL)
+ return Py_BuildValue("N(OO)", _PyObject_GetBuiltin("iter"),
+ it->it_callable, it->it_sentinel);
+ else
+ return Py_BuildValue("N(())", _PyObject_GetBuiltin("iter"));
+}
+
+static PyMethodDef calliter_methods[] = {
+ {"__reduce__", (PyCFunction)calliter_reduce, METH_NOARGS, reduce_doc},
+ {NULL, NULL} /* sentinel */
+};
+
PyTypeObject PyCallIter_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
"callable_iterator", /* tp_name */
@@ -224,7 +269,7 @@
0, /* tp_weaklistoffset */
PyObject_SelfIter, /* tp_iter */
(iternextfunc)calliter_iternext, /* tp_iternext */
- 0, /* tp_methods */
+ calliter_methods, /* tp_methods */
};


diff --git a/Objects/listobject.c b/Objects/listobject.c
--- a/Objects/listobject.c
+++ b/Objects/listobject.c
@@ -2660,11 +2660,18 @@
static int listiter_traverse(listiterobject *, visitproc, void *);
static PyObject *listiter_next(listiterobject *);
static PyObject *listiter_len(listiterobject *);
+static PyObject *listiter_reduce_general(void *_it, int forward);
+static PyObject *listiter_reduce(listiterobject *);
+static PyObject *listiter_setstate(listiterobject *, PyObject *state);

PyDoc_STRVAR(length_hint_doc, "Private method returning an estimate of len(list(it)).");
+PyDoc_STRVAR(reduce_doc, "Return state information for pickling.");
+PyDoc_STRVAR(setstate_doc, "Set state information for unpickling.");

static PyMethodDef listiter_methods[] = {
{"__length_hint__", (PyCFunction)listiter_len, METH_NOARGS, length_hint_doc},
+ {"__reduce__", (PyCFunction)listiter_reduce, METH_NOARGS, reduce_doc},
+ {"__setstate__", (PyCFunction)listiter_setstate, METH_O, setstate_doc},
{NULL, NULL} /* sentinel */
};

@@ -2771,6 +2778,27 @@
}
return PyLong_FromLong(0);
}
+
+static PyObject *
+listiter_reduce(listiterobject *it)
+{
+ return listiter_reduce_general(it, 1);
+}
+
+static PyObject *
+listiter_setstate(listiterobject *it, PyObject *state)
+{
+ long index = PyLong_AsLong(state);
+ if (index == -1 && PyErr_Occurred())
+ return NULL;
+ if (it->it_seq != NULL) {
+ if (index < 0)
+ index = 0;
+ it->it_index = index;
+ }
+ Py_RETURN_NONE;
+}
+
/*********************** List Reverse Iterator **************************/

typedef struct {
@@ -2784,9 +2812,13 @@
static int listreviter_traverse(listreviterobject *, visitproc, void *);
static PyObject *listreviter_next(listreviterobject *);
static PyObject *listreviter_len(listreviterobject *);
+static PyObject *listreviter_reduce(listreviterobject *);
+static PyObject *listreviter_setstate(listreviterobject *, PyObject *);

static PyMethodDef listreviter_methods[] = {
{"__length_hint__", (PyCFunction)listreviter_len, METH_NOARGS, length_hint_doc},
+ {"__reduce__", (PyCFunction)listreviter_reduce, METH_NOARGS, reduce_doc},
+ {"__setstate__", (PyCFunction)listreviter_setstate, METH_O, setstate_doc},
{NULL, NULL} /* sentinel */
};

@@ -2883,3 +2915,51 @@
len = 0;
return PyLong_FromSsize_t(len);
}
+
+static PyObject *
+listreviter_reduce(listreviterobject *it)
+{
+ return listiter_reduce_general(it, 0);
+}
+
+static PyObject *
+listreviter_setstate(listreviterobject *it, PyObject *state)
+{
+ Py_ssize_t index = PyLong_AsSsize_t(state);
+ if (index == -1 && PyErr_Occurred())
+ return NULL;
+ if (it->it_seq != NULL) {
+ if (index < -1)
+ index = -1;
+ else if (index > PyList_GET_SIZE(it->it_seq) - 1)
+ index = PyList_GET_SIZE(it->it_seq) - 1;
+ it->it_index = index;
+ }
+ Py_RETURN_NONE;
+}
+
+/* common pickling support */
+
+static PyObject *
+listiter_reduce_general(void *_it, int forward)
+{
+ PyObject *list;
+
+ /* the objects are not the same, index is of different types! */
+ if (forward) {
+ listiterobject *it = (listiterobject *)_it;
+ if (it->it_seq)
+ return Py_BuildValue("N(O)l", _PyObject_GetBuiltin("iter"),
+ it->it_seq, it->it_index);
+ } else {
+ listreviterobject *it = (listreviterobject *)_it;
+ if (it->it_seq)
+ return Py_BuildValue("N(O)n", _PyObject_GetBuiltin("reversed"),
+ it->it_seq, it->it_index);
+ }
+ /* empty iterator, create an empty list */
+ list = PyList_New(0);
+ if (list == NULL)
+ return NULL;
+ return Py_BuildValue("N(N)", _PyObject_GetBuiltin("iter"), list);
+}
diff --git a/Objects/object.c b/Objects/object.c
--- a/Objects/object.c
+++ b/Objects/object.c
@@ -1026,6 +1026,19 @@
return obj;
}

+/* Convenience function to get a builtin from its name */
+PyObject *
+_PyObject_GetBuiltin(const char *name)
+{
+ PyObject *mod, *attr;
+ mod = PyImport_ImportModule("builtins");
+ if (mod == NULL)
+ return NULL;
+ attr = PyObject_GetAttrString(mod, name);
+ Py_DECREF(mod);
+ return attr;
+}
+
/* Helper used when the __next__ method is removed from a type:
tp_iternext is never NULL and can be safely called without checking
on every iteration.
diff --git a/Objects/rangeobject.c b/Objects/rangeobject.c
--- a/Objects/rangeobject.c
+++ b/Objects/rangeobject.c
@@ -964,9 +964,59 @@
PyDoc_STRVAR(length_hint_doc,
"Private method returning an estimate of len(list(it)).");

+static PyObject *
+rangeiter_reduce(rangeiterobject *r)
+{
+ PyObject *start=NULL, *stop=NULL, *step=NULL;
+ PyObject *range;
+
+ /* create a range object for pickling */
+ start = PyLong_FromLong(r->start);
+ if (start == NULL)
+ goto err;
+ stop = PyLong_FromLong(r->start + r->len * r->step);
+ if (stop == NULL)
+ goto err;
+ step = PyLong_FromLong(r->step);
+ if (step == NULL)
+ goto err;
+ range = (PyObject*)make_range_object(&PyRange_Type,
+ start, stop, step);
+ if (range == NULL)
+ goto err;
+ /* return the result */
+ return Py_BuildValue("N(N)i", _PyObject_GetBuiltin("iter"), range, r->index);
+err:
+ Py_XDECREF(start);
+ Py_XDECREF(stop);
+ Py_XDECREF(step);
+ return NULL;
+}
+
+static PyObject *
+rangeiter_setstate(rangeiterobject *r, PyObject *state)
+{
+ long index = PyLong_AsLong(state);
+ if (index == -1 && PyErr_Occurred())
+ return NULL;
+ if (index < 0 || index >= r->len) {
+ PyErr_SetString(PyExc_ValueError, "index out of range");
+ return NULL;
+ }
+ r->index = index;
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(reduce_doc, "Return state information for pickling.");
+PyDoc_STRVAR(setstate_doc, "Set state information for unpickling.");
+
static PyMethodDef rangeiter_methods[] = {
{"__length_hint__", (PyCFunction)rangeiter_len, METH_NOARGS,
length_hint_doc},
+ {"__reduce__", (PyCFunction)rangeiter_reduce, METH_NOARGS,
+ reduce_doc},
+ {"__setstate__", (PyCFunction)rangeiter_setstate, METH_O,
+ setstate_doc},
{NULL, NULL} /* sentinel */
};

@@ -1095,9 +1145,51 @@
return PyNumber_Subtract(r->len, r->index);
}

+static PyObject *
+longrangeiter_reduce(longrangeiterobject *r)
+{
+ PyObject *product, *stop=NULL;
+ PyObject *range;
+
+ /* create a range object for pickling. Must calculate the "stop" value */
+ product = PyNumber_Multiply(r->len, r->step);
+ if (product == NULL)
+ return NULL;
+ stop = PyNumber_Add(r->start, product);
+ Py_DECREF(product);
+ if (stop == NULL)
+ return NULL;
+ Py_INCREF(r->start);
+ Py_INCREF(r->step);
+ range = (PyObject*)make_range_object(&PyRange_Type,
+ r->start, stop, r->step);
+ if (range == NULL) {
+ Py_DECREF(r->start);
+ Py_DECREF(stop);
+ Py_DECREF(r->step);
+ return NULL;
+ }
+
+ /* return the result */
+ return Py_BuildValue("N(N)O", _PyObject_GetBuiltin("iter"), range, r->index);
+}
+
+static PyObject *
+longrangeiter_setstate(longrangeiterobject *r, PyObject *state)
+{
+ Py_CLEAR(r->index);
+ r->index = state;
+ Py_INCREF(r->index);
+ Py_RETURN_NONE;
+}
+
static PyMethodDef longrangeiter_methods[] = {
{"__length_hint__", (PyCFunction)longrangeiter_len, METH_NOARGS,
length_hint_doc},
+ {"__reduce__", (PyCFunction)longrangeiter_reduce, METH_NOARGS,
+ reduce_doc},
+ {"__setstate__", (PyCFunction)longrangeiter_setstate, METH_O,
+ setstate_doc},
{NULL, NULL} /* sentinel */
};

diff --git a/Objects/setobject.c b/Objects/setobject.c
--- a/Objects/setobject.c
+++ b/Objects/setobject.c
@@ -819,8 +819,51 @@

PyDoc_STRVAR(length_hint_doc, "Private method returning an estimate of len(list(it)).");

+static PyObject *setiter_iternext(setiterobject *si);
+
+static PyObject *
+setiter_reduce(setiterobject *si)
+{
+ PyObject *list;
+ setiterobject tmp;
+
+ list = PyList_New(0);
+ if (!list)
+ return NULL;
+
+ /* copy the itertor state */
+ tmp = *si;
+ Py_XINCREF(tmp.si_set);
+
+ /* iterate the temporary into a list */
+ for(;;) {
+ PyObject *element = setiter_iternext(&tmp);
+ if (element) {
+ if (PyList_Append(list, element)) {
+ Py_DECREF(element);
+ Py_DECREF(list);
+ Py_XDECREF(tmp.si_set);
+ return NULL;
+ }
+ Py_DECREF(element);
+ } else
+ break;
+ }
+ Py_XDECREF(tmp.si_set);
+ /* check for error */
+ if (tmp.si_set != NULL) {
+ /* we have an error */
+ Py_DECREF(list);
+ return NULL;
+ }
+ return Py_BuildValue("N(N)", _PyObject_GetBuiltin("iter"), list);
+}
+
+PyDoc_STRVAR(reduce_doc, "Return state information for pickling.");
+
static PyMethodDef setiter_methods[] = {
{"__length_hint__", (PyCFunction)setiter_len, METH_NOARGS, length_hint_doc},
+ {"__reduce__", (PyCFunction)setiter_reduce, METH_NOARGS, reduce_doc},
{NULL, NULL} /* sentinel */
};

@@ -1964,8 +2007,6 @@
return result;
}

-PyDoc_STRVAR(reduce_doc, "Return state information for pickling.");
-
static PyObject *
set_sizeof(PySetObject *so)
{
diff --git a/Objects/tupleobject.c b/Objects/tupleobject.c
--- a/Objects/tupleobject.c
+++ b/Objects/tupleobject.c
@@ -967,8 +967,39 @@

PyDoc_STRVAR(length_hint_doc, "Private method returning an estimate of len(list(it)).");

+static PyObject *
+tupleiter_reduce(tupleiterobject *it)
+{
+ if (it->it_seq)
+ return Py_BuildValue("N(O)l", _PyObject_GetBuiltin("iter"),
+ it->it_seq, it->it_index);
+ else
+ return Py_BuildValue("N(())", _PyObject_GetBuiltin("iter"));
+}
+
+static PyObject *
+tupleiter_setstate(tupleiterobject *it, PyObject *state)
+{
+ long index = PyLong_AsLong(state);
+ if (index == -1 && PyErr_Occurred())
+ return NULL;
+ if (it->it_seq != NULL) {
+ if (index < 0)
+ index = 0;
+ else if (it->it_seq != NULL && index > PyTuple_GET_SIZE(it->it_seq))
+ index = PyTuple_GET_SIZE(it->it_seq);
+ it->it_index = index;
+ }
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(reduce_doc, "Return state information for pickling.");
+PyDoc_STRVAR(setstate_doc, "Set state information for unpickling.");
+
static PyMethodDef tupleiter_methods[] = {
{"__length_hint__", (PyCFunction)tupleiter_len, METH_NOARGS, length_hint_doc},
+ {"__reduce__", (PyCFunction)tupleiter_reduce, METH_NOARGS, reduce_doc},
+ {"__setstate__", (PyCFunction)tupleiter_setstate, METH_O, setstate_doc},
{NULL, NULL} /* sentinel */
};

diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c
--- a/Objects/unicodeobject.c
+++ b/Objects/unicodeobject.c
@@ -5393,9 +5393,11 @@
#if (SIZEOF_LONG == 8)
# define FAST_CHAR_MASK 0x8000800080008000L
# define SWAPPED_FAST_CHAR_MASK 0x0080008000800080L
+# define STRIPPED_MASK 0x00FF00FF00FF00FFL
#elif (SIZEOF_LONG == 4)
# define FAST_CHAR_MASK 0x80008000L
# define SWAPPED_FAST_CHAR_MASK 0x00800080L
+# define STRIPPED_MASK 0x00FF00FFL
#else
# error C 'long' size should be either 4 or 8!
#endif
@@ -5497,7 +5499,6 @@
void *data = PyUnicode_DATA(unicode);
while (_q < aligned_end) {
unsigned long block = * (unsigned long *) _q;
- unsigned short *pblock = (unsigned short*)&block;
Py_UCS4 maxch;
if (native_ordering) {
/* Can use buffer directly */
@@ -5506,23 +5507,22 @@
}
else {
/* Need to byte-swap */
- unsigned char *_p = (unsigned char*)pblock;
if (block & SWAPPED_FAST_CHAR_MASK)
break;
- _p[0] = _q[1];
- _p[1] = _q[0];
- _p[2] = _q[3];
- _p[3] = _q[2];
-#if (SIZEOF_LONG == 8)
- _p[4] = _q[5];
- _p[5] = _q[4];
- _p[6] = _q[7];
- _p[7] = _q[6];
-#endif
- }
- maxch = Py_MAX(pblock[0], pblock[1]);
+ block = ((block >> 8) & STRIPPED_MASK) |
+ ((block & STRIPPED_MASK) << 8);
+ }
+ maxch = (Py_UCS2)(block & 0xFFFF);
#if SIZEOF_LONG == 8
- maxch = Py_MAX(maxch, Py_MAX(pblock[2], pblock[3]));
+ ch = (Py_UCS2)((block >> 16) & 0xFFFF);
+ maxch = Py_MAX(maxch, ch);
+ ch = (Py_UCS2)((block >> 32) & 0xFFFF);
+ maxch = Py_MAX(maxch, ch);
+ ch = (Py_UCS2)(block >> 48);
+ maxch = Py_MAX(maxch, ch);
+#else
+ ch = (Py_UCS2)(block >> 16);
+ maxch = Py_MAX(maxch, ch);
#endif
if (maxch > PyUnicode_MAX_CHAR_VALUE(unicode)) {
if (unicode_widen(&unicode, maxch) < 0)
@@ -5530,11 +5530,24 @@
kind = PyUnicode_KIND(unicode);
data = PyUnicode_DATA(unicode);
}
- PyUnicode_WRITE(kind, data, outpos++, pblock[0]);
- PyUnicode_WRITE(kind, data, outpos++, pblock[1]);
+#ifdef BYTEORDER_IS_LITTLE_ENDIAN
+ PyUnicode_WRITE(kind, data, outpos++, (Py_UCS2)(block & 0xFFFF));
#if SIZEOF_LONG == 8
- PyUnicode_WRITE(kind, data, outpos++, pblock[2]);
- PyUnicode_WRITE(kind, data, outpos++, pblock[3]);
+ PyUnicode_WRITE(kind, data, outpos++, (Py_UCS2)((block >> 16) & 0xFFFF));
+ PyUnicode_WRITE(kind, data, outpos++, (Py_UCS2)((block >> 32) & 0xFFFF));
+ PyUnicode_WRITE(kind, data, outpos++, (Py_UCS2)((block >> 48)));
+#else
+ PyUnicode_WRITE(kind, data, outpos++, (Py_UCS2)(block >> 16));
+#endif
+#else
+#if SIZEOF_LONG == 8
+ PyUnicode_WRITE(kind, data, outpos++, (Py_UCS2)((block >> 48)));
+ PyUnicode_WRITE(kind, data, outpos++, (Py_UCS2)((block >> 32) & 0xFFFF));
+ PyUnicode_WRITE(kind, data, outpos++, (Py_UCS2)((block >> 16) & 0xFFFF));
+#else
+ PyUnicode_WRITE(kind, data, outpos++, (Py_UCS2)(block >> 16));
+#endif
+ PyUnicode_WRITE(kind, data, outpos++, (Py_UCS2)(block & 0xFFFF));
#endif
_q += SIZEOF_LONG;
}
@@ -14382,9 +14395,43 @@

PyDoc_STRVAR(length_hint_doc, "Private method returning an estimate of len(list(it)).");

+static PyObject *
+unicodeiter_reduce(unicodeiterobject *it)
+{
+ if (it->it_seq != NULL) {
+ return Py_BuildValue("N(O)n", _PyObject_GetBuiltin("iter"),
+ it->it_seq, it->it_index);
+ } else {
+ PyObject *u = PyUnicode_FromUnicode(NULL, 0);
+ if (u == NULL)
+ return NULL;
+ return Py_BuildValue("N(N)", _PyObject_GetBuiltin("iter"), u);
+ }
+}
+
+PyDoc_STRVAR(reduce_doc, "Return state information for pickling.");
+
+static PyObject *
+unicodeiter_setstate(unicodeiterobject *it, PyObject *state)
+{
+ Py_ssize_t index = PyLong_AsSsize_t(state);
+ if (index == -1 && PyErr_Occurred())
+ return NULL;
+ if (index < 0)
+ index = 0;
+ it->it_index = index;
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(setstate_doc, "Set state information for unpickling.");
+
static PyMethodDef unicodeiter_methods[] = {
{"__length_hint__", (PyCFunction)unicodeiter_len, METH_NOARGS,
length_hint_doc},
+ {"__reduce__", (PyCFunction)unicodeiter_reduce, METH_NOARGS,
+ reduce_doc},
+ {"__setstate__", (PyCFunction)unicodeiter_setstate, METH_O,
+ setstate_doc},
{NULL, NULL} /* sentinel */
};

diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c
--- a/Python/bltinmodule.c
+++ b/Python/bltinmodule.c
@@ -438,6 +438,19 @@
}
}

+static PyObject *
+filter_reduce(filterobject *lz)
+{
+ return Py_BuildValue("O(OO)", Py_TYPE(lz), lz->func, lz->it);
+}
+
+PyDoc_STRVAR(reduce_doc, "Return state information for pickling.");
+
+static PyMethodDef filter_methods[] = {
+ {"__reduce__", (PyCFunction)filter_reduce, METH_NOARGS, reduce_doc},
+ {NULL, NULL} /* sentinel */
+};
+
PyDoc_STRVAR(filter_doc,
"filter(function or None, iterable) --> filter object\n\
\n\
@@ -474,7 +487,7 @@
0, /* tp_weaklistoffset */
PyObject_SelfIter, /* tp_iter */
(iternextfunc)filter_next, /* tp_iternext */
- 0, /* tp_methods */
+ filter_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
@@ -1054,6 +1067,31 @@
return result;
}

+static PyObject *
+map_reduce(mapobject *lz)
+{
+ Py_ssize_t numargs = PyTuple_GET_SIZE(lz->iters);
+ PyObject *args = PyTuple_New(numargs+1);
+ Py_ssize_t i;
+ if (args == NULL)
+ return NULL;
+ Py_INCREF(lz->func);
+ PyTuple_SET_ITEM(args, 0, lz->func);
+ for (i = 0; i<numargs; i++){
+ PyObject *it = PyTuple_GET_ITEM(lz->iters, i);
+ Py_INCREF(it);
+ PyTuple_SET_ITEM(args, i+1, it);
+ }
+
+ return Py_BuildValue("ON", Py_TYPE(lz), args);
+}
+
+static PyMethodDef map_methods[] = {
+ {"__reduce__", (PyCFunction)map_reduce, METH_NOARGS, reduce_doc},
+ {NULL, NULL} /* sentinel */
+};
+
+
PyDoc_STRVAR(map_doc,
"map(func, *iterables) --> map object\n\
\n\
@@ -1090,7 +1128,7 @@
0, /* tp_weaklistoffset */
PyObject_SelfIter, /* tp_iter */
(iternextfunc)map_next, /* tp_iternext */
- 0, /* tp_methods */
+ map_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
@@ -2238,6 +2276,18 @@
return result;
}

+static PyObject *
+zip_reduce(zipobject *lz)
+{
+ /* Just recreate the zip with the internal iterator tuple */
+ return Py_BuildValue("OO", Py_TYPE(lz), lz->ittuple);
+}
+
+static PyMethodDef zip_methods[] = {
+ {"__reduce__", (PyCFunction)zip_reduce, METH_NOARGS, reduce_doc},
+ {NULL, NULL} /* sentinel */
+};
+
PyDoc_STRVAR(zip_doc,
"zip(iter1 [,iter2 [...]]) --> zip object\n\
\n\
@@ -2276,7 +2326,7 @@
0, /* tp_weaklistoffset */
PyObject_SelfIter, /* tp_iter */
(iternextfunc)zip_next, /* tp_iternext */
- 0, /* tp_methods */
+ zip_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
diff --git a/Python/pythonrun.c b/Python/pythonrun.c
--- a/Python/pythonrun.c
+++ b/Python/pythonrun.c
@@ -1356,56 +1356,67 @@
_Py_IDENTIFIER(offset);
_Py_IDENTIFIER(text);

+ *message = NULL;
+
/* new style errors. `err' is an instance */
-
- if (! (v = _PyObject_GetAttrId(err, &PyId_msg)))
- goto finally;
- *message = v;
-
- if (!(v = _PyObject_GetAttrId(err, &PyId_filename)))
- goto finally;
- if (v == Py_None)
- *filename = NULL;
- else if (! (*filename = _PyUnicode_AsString(v)))
+ *message = _PyObject_GetAttrId(err, &PyId_msg);
+ if (!*message)
goto finally;

- Py_DECREF(v);
- if (!(v = _PyObject_GetAttrId(err, &PyId_lineno)))
+ v = _PyObject_GetAttrId(err, &PyId_filename);
+ if (!v)
+ goto finally;
+ if (v == Py_None) {
+ Py_DECREF(v);
+ *filename = NULL;
+ }
+ else {
+ *filename = _PyUnicode_AsString(v);
+ Py_DECREF(v);
+ if (!*filename)
+ goto finally;
+ }
+
+ v = _PyObject_GetAttrId(err, &PyId_lineno);
+ if (!v)
goto finally;
hold = PyLong_AsLong(v);
Py_DECREF(v);
- v = NULL;
if (hold < 0 && PyErr_Occurred())
goto finally;
*lineno = (int)hold;

- if (!(v = _PyObject_GetAttrId(err, &PyId_offset)))
+ v = _PyObject_GetAttrId(err, &PyId_offset);
+ if (!v)
goto finally;
if (v == Py_None) {
*offset = -1;
Py_DECREF(v);
- v = NULL;
} else {
hold = PyLong_AsLong(v);
Py_DECREF(v);
- v = NULL;
if (hold < 0 && PyErr_Occurred())
goto finally;
*offset = (int)hold;
}

- if (!(v = _PyObject_GetAttrId(err, &PyId_text)))
+ v = _PyObject_GetAttrId(err, &PyId_text);
+ if (!v)
goto finally;
- if (v == Py_None)
+ if (v == Py_None) {
+ Py_DECREF(v);
*text = NULL;
- else if (!PyUnicode_Check(v) ||
- !(*text = _PyUnicode_AsString(v)))
- goto finally;
- Py_DECREF(v);
+ }
+ else {
+ *text = _PyUnicode_AsString(v);
+ Py_DECREF(v);
+ if (!*text)
+ goto finally;
+ }
return 1;

finally:
- Py_XDECREF(v);
+ Py_XDECREF(*message);
return 0;
}

diff --git a/Tools/scripts/abitype.py b/Tools/scripts/abitype.py
--- a/Tools/scripts/abitype.py
+++ b/Tools/scripts/abitype.py
@@ -3,34 +3,6 @@
# Usage: abitype.py < old_code > new_code
import re, sys

-############ Simplistic C scanner ##################################
-tokenizer = re.compile(
- r"(?P<preproc>#.*\n)"
- r"|(?P<comment>/\*.*?\*/)"
- r"|(?P<ident>[a-zA-Z_][a-zA-Z0-9_]*)"
- r"|(?P<ws>[ \t\n]+)"
- r"|(?P<other>.)",
- re.MULTILINE)
-
-tokens = []
-source = sys.stdin.read()
-pos = 0
-while pos != len(source):
- m = tokenizer.match(source, pos)
- tokens.append([m.lastgroup, m.group()])
- pos += len(tokens[-1][1])
- if tokens[-1][0] == 'preproc':
- # continuation lines are considered
- # only in preprocess statements
- while tokens[-1][1].endswith('\\\n'):
- nl = source.find('\n', pos)
- if nl == -1:
- line = source[pos:]
- else:
- line = source[pos:nl+1]
- tokens[-1][1] += line
- pos += len(line)
-
###### Replacement of PyTypeObject static instances ##############

# classify each token, giving it a one-letter code:
@@ -79,7 +51,7 @@
while tokens[pos][0] in ('ws', 'comment'):
pos += 1
if tokens[pos][1] != 'PyVarObject_HEAD_INIT':
- raise Exception, '%s has no PyVarObject_HEAD_INIT' % name
+ raise Exception('%s has no PyVarObject_HEAD_INIT' % name)
while tokens[pos][1] != ')':
pos += 1
pos += 1
@@ -183,18 +155,48 @@
return '\n'.join(res)


-# Main loop: replace all static PyTypeObjects until
-# there are none left.
-while 1:
- c = classify()
- m = re.search('(SW)?TWIW?=W?{.*?};', c)
- if not m:
- break
- start = m.start()
- end = m.end()
- name, fields = get_fields(start, m)
- tokens[start:end] = [('',make_slots(name, fields))]
+if __name__ == '__main__':

-# Output result to stdout
-for t, v in tokens:
- sys.stdout.write(v)
+ ############ Simplistic C scanner ##################################
+ tokenizer = re.compile(
+ r"(?P<preproc>#.*\n)"
+ r"|(?P<comment>/\*.*?\*/)"
+ r"|(?P<ident>[a-zA-Z_][a-zA-Z0-9_]*)"
+ r"|(?P<ws>[ \t\n]+)"
+ r"|(?P<other>.)",
+ re.MULTILINE)
+
+ tokens = []
+ source = sys.stdin.read()
+ pos = 0
+ while pos != len(source):
+ m = tokenizer.match(source, pos)
+ tokens.append([m.lastgroup, m.group()])
+ pos += len(tokens[-1][1])
+ if tokens[-1][0] == 'preproc':
+ # continuation lines are considered
+ # only in preprocess statements
+ while tokens[-1][1].endswith('\\\n'):
+ nl = source.find('\n', pos)
+ if nl == -1:
+ line = source[pos:]
+ else:
+ line = source[pos:nl+1]
+ tokens[-1][1] += line
+ pos += len(line)
+
+ # Main loop: replace all static PyTypeObjects until
+ # there are none left.
+ while 1:
+ c = classify()
+ m = re.search('(SW)?TWIW?=W?{.*?};', c)
+ if not m:
+ break
+ start = m.start()
+ end = m.end()
+ name, fields = get_fields(start, m)
+ tokens[start:end] = [('',make_slots(name, fields))]
+
+ # Output result to stdout
+ for t, v in tokens:
+ sys.stdout.write(v)
diff --git a/Tools/scripts/find_recursionlimit.py b/Tools/scripts/find_recursionlimit.py
--- a/Tools/scripts/find_recursionlimit.py
+++ b/Tools/scripts/find_recursionlimit.py
@@ -106,14 +106,16 @@
else:
print("Yikes!")

-limit = 1000
-while 1:
- check_limit(limit, "test_recurse")
- check_limit(limit, "test_add")
- check_limit(limit, "test_repr")
- check_limit(limit, "test_init")
- check_limit(limit, "test_getattr")
- check_limit(limit, "test_getitem")
- check_limit(limit, "test_cpickle")
- print("Limit of %d is fine" % limit)
- limit = limit + 100
+if __name__ == '__main__':
+
+ limit = 1000
+ while 1:
+ check_limit(limit, "test_recurse")
+ check_limit(limit, "test_add")
+ check_limit(limit, "test_repr")
+ check_limit(limit, "test_init")
+ check_limit(limit, "test_getattr")
+ check_limit(limit, "test_getitem")
+ check_limit(limit, "test_cpickle")
+ print("Limit of %d is fine" % limit)
+ limit = limit + 100
diff --git a/Tools/scripts/findnocoding.py b/Tools/scripts/findnocoding.py
--- a/Tools/scripts/findnocoding.py
+++ b/Tools/scripts/findnocoding.py
@@ -76,29 +76,31 @@
-c: recognize Python source files trying to compile them
-d: debug output""" % sys.argv[0]

-try:
- opts, args = getopt.getopt(sys.argv[1:], 'cd')
-except getopt.error as msg:
- print(msg, file=sys.stderr)
- print(usage, file=sys.stderr)
- sys.exit(1)
+if __name__ == '__main__':

-is_python = pysource.looks_like_python
-debug = False
+ try:
+ opts, args = getopt.getopt(sys.argv[1:], 'cd')
+ except getopt.error as msg:
+ print(msg, file=sys.stderr)
+ print(usage, file=sys.stderr)
+ sys.exit(1)

-for o, a in opts:
- if o == '-c':
- is_python = pysource.can_be_compiled
- elif o == '-d':
- debug = True
+ is_python = pysource.looks_like_python
+ debug = False

-if not args:
- print(usage, file=sys.stderr)
- sys.exit(1)
+ for o, a in opts:
+ if o == '-c':
+ is_python = pysource.can_be_compiled
+ elif o == '-d':
+ debug = True

-for fullpath in pysource.walk_python_files(args, is_python):
- if debug:
- print("Testing for coding: %s" % fullpath)
- result = needs_declaration(fullpath)
- if result:
- print(fullpath)
+ if not args:
+ print(usage, file=sys.stderr)
+ sys.exit(1)
+
+ for fullpath in pysource.walk_python_files(args, is_python):
+ if debug:
+ print("Testing for coding: %s" % fullpath)
+ result = needs_declaration(fullpath)
+ if result:
+ print(fullpath)
diff --git a/Tools/scripts/fixcid.py b/Tools/scripts/fixcid.py
--- a/Tools/scripts/fixcid.py
+++ b/Tools/scripts/fixcid.py
@@ -292,7 +292,7 @@
if not words: continue
if len(words) == 3 and words[0] == 'struct':
words[:2] = [words[0] + ' ' + words[1]]
- elif len(words) <> 2:
+ elif len(words) != 2:
err(substfile + '%s:%r: warning: bad line: %r' % (substfile, lineno, line))
continue
if Reverse:
diff --git a/Tools/scripts/md5sum.py b/Tools/scripts/md5sum.py
--- a/Tools/scripts/md5sum.py
+++ b/Tools/scripts/md5sum.py
@@ -20,7 +20,7 @@
import sys
import os
import getopt
-import md5
+from hashlib import md5

def sum(*files):
sts = 0
diff --git a/Tools/scripts/parseentities.py b/Tools/scripts/parseentities.py
--- a/Tools/scripts/parseentities.py
+++ b/Tools/scripts/parseentities.py
@@ -13,7 +13,6 @@

"""
import re,sys
-import TextTools

entityRE = re.compile('<!ENTITY +(\w+) +CDATA +"([^"]+)" +-- +((?:.|\n)+?) *-->')

@@ -45,7 +44,7 @@
charcode = repr(charcode)
else:
charcode = repr(charcode)
- comment = TextTools.collapse(comment)
+ comment = ' '.join(comment.split())
f.write(" '%s':\t%s, \t# %s\n" % (name,charcode,comment))
f.write('\n}\n')

diff --git a/Tools/scripts/pdeps.py b/Tools/scripts/pdeps.py
--- a/Tools/scripts/pdeps.py
+++ b/Tools/scripts/pdeps.py
@@ -76,10 +76,9 @@
nextline = fp.readline()
if not nextline: break
line = line[:-1] + nextline
- if m_import.match(line) >= 0:
- (a, b), (a1, b1) = m_import.regs[:2]
- elif m_from.match(line) >= 0:
- (a, b), (a1, b1) = m_from.regs[:2]
+ m_found = m_import.match(line) or m_from.match(line)
+ if m_found:
+ (a, b), (a1, b1) = m_found.regs[:2]
else: continue
words = line[a1:b1].split(',')
# print '#', line, words
@@ -87,6 +86,7 @@
word = word.strip()
if word not in list:
list.append(word)
+ fp.close()


# Compute closure (this is in fact totally general)
@@ -123,7 +123,7 @@
def inverse(table):
inv = {}
for key in table.keys():
- if not inv.has_key(key):
+ if key not in inv:
inv[key] = []
for item in table[key]:
store(inv, item, key)

--
Repository URL: http://hg.python.org/cpython
cpython (merge default -> default): Merge [ In reply to ]
http://hg.python.org/cpython/rev/edca98123f22
changeset: 76282:edca98123f22
parent: 76281:d06db42ae1a3
parent: 76278:59c526e7bca5
user: Brett Cannon <brett@python.org>
date: Thu Apr 12 21:13:08 2012 -0400
summary:
Merge

files:
PC/VC6/pythoncore.dsp | 4 ++++
PC/VS7.1/pythoncore.vcproj | 3 +++
PC/VS8.0/pythoncore.vcproj | 4 ++++
3 files changed, 11 insertions(+), 0 deletions(-)


diff --git a/PC/VC6/pythoncore.dsp b/PC/VC6/pythoncore.dsp
--- a/PC/VC6/pythoncore.dsp
+++ b/PC/VC6/pythoncore.dsp
@@ -655,6 +655,10 @@
# End Source File
# Begin Source File

+SOURCE=..\..\Python\random.c
+# End Source File
+# Begin Source File
+
SOURCE=..\..\Objects\rangeobject.c
# End Source File
# Begin Source File
diff --git a/PC/VS7.1/pythoncore.vcproj b/PC/VS7.1/pythoncore.vcproj
--- a/PC/VS7.1/pythoncore.vcproj
+++ b/PC/VS7.1/pythoncore.vcproj
@@ -767,6 +767,9 @@
RelativePath="..\..\Python\pythonrun.c">
</File>
<File
+ RelativePath="..\..\Python\random.c">
+ </File>
+ <File
RelativePath="..\..\Objects\rangeobject.c">
</File>
<File
diff --git a/PC/VS8.0/pythoncore.vcproj b/PC/VS8.0/pythoncore.vcproj
--- a/PC/VS8.0/pythoncore.vcproj
+++ b/PC/VS8.0/pythoncore.vcproj
@@ -1883,6 +1883,10 @@
>
</File>
<File
+ RelativePath="..\..\Python\random.c"
+ >
+ </File>
+ <File
RelativePath="..\..\Python\structmember.c"
>
</File>

--
Repository URL: http://hg.python.org/cpython
cpython (merge default -> default): merge [ In reply to ]
http://hg.python.org/cpython/rev/95c29787320a
changeset: 76330:95c29787320a
parent: 76329:005fd1fe31ab
parent: 76327:1ca10eb58483
user: Brett Cannon <brett@python.org>
date: Sun Apr 15 15:25:10 2012 -0400
summary:
merge

files:
Lib/importlib/_bootstrap.py | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)


diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py
--- a/Lib/importlib/_bootstrap.py
+++ b/Lib/importlib/_bootstrap.py
@@ -23,7 +23,7 @@


def _make_relax_case():
- if any(map(sys.platform.startswith, CASE_INSENSITIVE_PLATFORMS)):
+ if sys.platform.startswith(CASE_INSENSITIVE_PLATFORMS):
def _relax_case():
"""True if filenames must be checked case-insensitively."""
return b'PYTHONCASEOK' in _os.environ
@@ -163,7 +163,7 @@
def verbose_message(message, *args):
"""Print the message to stderr if -v/PYTHONVERBOSE is turned on."""
if sys.flags.verbose:
- if not message.startswith('#') and not message.startswith('import '):
+ if not message.startswith(('#', 'import ')):
message = '# ' + message
print(message.format(*args), file=sys.stderr)


--
Repository URL: http://hg.python.org/cpython
cpython (merge default -> default): merge [ In reply to ]
http://hg.python.org/cpython/rev/2e6acfa3509e
changeset: 76337:2e6acfa3509e
parent: 76336:60acd04d5613
parent: 76334:c3a0197256ee
user: Brett Cannon <brett@python.org>
date: Sun Apr 15 19:06:40 2012 -0400
summary:
merge

files:
Doc/c-api/dict.rst | 8 +-
Doc/library/stdtypes.rst | 16 +-
Doc/library/types.rst | 52 +++++++
Doc/whatsnew/3.3.rst | 7 +
Lib/test/test_descr.py | 4 +-
Lib/test/test_types.py | 184 ++++++++++++++++++++++++++-
Lib/types.py | 1 +
Misc/NEWS | 2 +
Objects/descrobject.c | 170 ++++++++++++++++--------
9 files changed, 369 insertions(+), 75 deletions(-)


diff --git a/Doc/c-api/dict.rst b/Doc/c-api/dict.rst
--- a/Doc/c-api/dict.rst
+++ b/Doc/c-api/dict.rst
@@ -36,11 +36,11 @@
Return a new empty dictionary, or *NULL* on failure.


-.. c:function:: PyObject* PyDictProxy_New(PyObject *dict)
+.. c:function:: PyObject* PyDictProxy_New(PyObject *mapping)

- Return a proxy object for a mapping which enforces read-only behavior.
- This is normally used to create a proxy to prevent modification of the
- dictionary for non-dynamic class types.
+ Return a :class:`types.MappingProxyType` object for a mapping which
+ enforces read-only behavior. This is normally used to create a view to
+ prevent modification of the dictionary for non-dynamic class types.


.. c:function:: void PyDict_Clear(PyObject *p)
diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst
--- a/Doc/library/stdtypes.rst
+++ b/Doc/library/stdtypes.rst
@@ -2258,13 +2258,13 @@

.. method:: items()

- Return a new view of the dictionary's items (``(key, value)`` pairs). See
- below for documentation of view objects.
+ Return a new view of the dictionary's items (``(key, value)`` pairs).
+ See the :ref:`documentation of view objects <dict-views>`.

.. method:: keys()

- Return a new view of the dictionary's keys. See below for documentation of
- view objects.
+ Return a new view of the dictionary's keys. See the :ref:`documentation
+ of view objects <dict-views>`.

.. method:: pop(key[, default])

@@ -2298,8 +2298,12 @@

.. method:: values()

- Return a new view of the dictionary's values. See below for documentation of
- view objects.
+ Return a new view of the dictionary's values. See the
+ :ref:`documentation of view objects <dict-views>`.
+
+.. seealso::
+ :class:`types.MappingProxyType` can be used to create a read-only view
+ of a :class:`dict`.


.. _dict-views:
diff --git a/Doc/library/types.rst b/Doc/library/types.rst
--- a/Doc/library/types.rst
+++ b/Doc/library/types.rst
@@ -85,3 +85,55 @@

In other implementations of Python, this type may be identical to
``GetSetDescriptorType``.
+
+.. class:: MappingProxyType(mapping)
+
+ Read-only proxy of a mapping. It provides a dynamic view on the mapping's
+ entries, which means that when the mapping changes, the view reflects these
+ changes.
+
+ .. versionadded:: 3.3
+
+ .. describe:: key in proxy
+
+ Return ``True`` if the underlying mapping has a key *key*, else
+ ``False``.
+
+ .. describe:: proxy[key]
+
+ Return the item of the underlying mapping with key *key*. Raises a
+ :exc:`KeyError` if *key* is not in the underlying mapping.
+
+ .. describe:: iter(proxy)
+
+ Return an iterator over the keys of the underlying mapping. This is a
+ shortcut for ``iter(proxy.keys())``.
+
+ .. describe:: len(proxy)
+
+ Return the number of items in the underlying mapping.
+
+ .. method:: copy()
+
+ Return a shallow copy of the underlying mapping.
+
+ .. method:: get(key[, default])
+
+ Return the value for *key* if *key* is in the underlying mapping, else
+ *default*. If *default* is not given, it defaults to ``None``, so that
+ this method never raises a :exc:`KeyError`.
+
+ .. method:: items()
+
+ Return a new view of the underlying mapping's items (``(key, value)``
+ pairs).
+
+ .. method:: keys()
+
+ Return a new view of the underlying mapping's keys.
+
+ .. method:: values()
+
+ Return a new view of the underlying mapping's values.
+
+
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
@@ -1068,6 +1068,13 @@
(Contributed by Victor Stinner in :issue:`10278`)


+types
+-----
+
+Add a new :class:`types.MappingProxyType` class: Read-only proxy of a mapping.
+(:issue:`14386`)
+
+
urllib
------

diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py
--- a/Lib/test/test_descr.py
+++ b/Lib/test/test_descr.py
@@ -4574,11 +4574,11 @@
self.assertEqual(type(C.__dict__), type(B.__dict__))

def test_repr(self):
- # Testing dict_proxy.__repr__.
+ # Testing mappingproxy.__repr__.
# We can't blindly compare with the repr of another dict as ordering
# of keys and values is arbitrary and may differ.
r = repr(self.C.__dict__)
- self.assertTrue(r.startswith('dict_proxy('), r)
+ self.assertTrue(r.startswith('mappingproxy('), r)
self.assertTrue(r.endswith(')'), r)
for k, v in self.C.__dict__.items():
self.assertIn('{!r}: {!r}'.format(k, v), r)
diff --git a/Lib/test/test_types.py b/Lib/test/test_types.py
--- a/Lib/test/test_types.py
+++ b/Lib/test/test_types.py
@@ -1,9 +1,11 @@
# Python test set -- part 6, built-in types

from test.support import run_unittest, run_with_locale
+import collections
+import locale
+import sys
+import types
import unittest
-import sys
-import locale

class TypesTests(unittest.TestCase):

@@ -569,8 +571,184 @@
self.assertGreater(tuple.__itemsize__, 0)


+class MappingProxyTests(unittest.TestCase):
+ mappingproxy = types.MappingProxyType
+
+ def test_constructor(self):
+ class userdict(dict):
+ pass
+
+ mapping = {'x': 1, 'y': 2}
+ self.assertEqual(self.mappingproxy(mapping), mapping)
+ mapping = userdict(x=1, y=2)
+ self.assertEqual(self.mappingproxy(mapping), mapping)
+ mapping = collections.ChainMap({'x': 1}, {'y': 2})
+ self.assertEqual(self.mappingproxy(mapping), mapping)
+
+ self.assertRaises(TypeError, self.mappingproxy, 10)
+ self.assertRaises(TypeError, self.mappingproxy, ("a", "tuple"))
+ self.assertRaises(TypeError, self.mappingproxy, ["a", "list"])
+
+ def test_methods(self):
+ attrs = set(dir(self.mappingproxy({}))) - set(dir(object()))
+ self.assertEqual(attrs, {
+ '__contains__',
+ '__getitem__',
+ '__iter__',
+ '__len__',
+ 'copy',
+ 'get',
+ 'items',
+ 'keys',
+ 'values',
+ })
+
+ def test_get(self):
+ view = self.mappingproxy({'a': 'A', 'b': 'B'})
+ self.assertEqual(view['a'], 'A')
+ self.assertEqual(view['b'], 'B')
+ self.assertRaises(KeyError, view.__getitem__, 'xxx')
+ self.assertEqual(view.get('a'), 'A')
+ self.assertIsNone(view.get('xxx'))
+ self.assertEqual(view.get('xxx', 42), 42)
+
+ def test_missing(self):
+ class dictmissing(dict):
+ def __missing__(self, key):
+ return "missing=%s" % key
+
+ view = self.mappingproxy(dictmissing(x=1))
+ self.assertEqual(view['x'], 1)
+ self.assertEqual(view['y'], 'missing=y')
+ self.assertEqual(view.get('x'), 1)
+ self.assertEqual(view.get('y'), None)
+ self.assertEqual(view.get('y', 42), 42)
+ self.assertTrue('x' in view)
+ self.assertFalse('y' in view)
+
+ def test_customdict(self):
+ class customdict(dict):
+ def __contains__(self, key):
+ if key == 'magic':
+ return True
+ else:
+ return dict.__contains__(self, key)
+
+ def __iter__(self):
+ return iter(('iter',))
+
+ def __len__(self):
+ return 500
+
+ def copy(self):
+ return 'copy'
+
+ def keys(self):
+ return 'keys'
+
+ def items(self):
+ return 'items'
+
+ def values(self):
+ return 'values'
+
+ def __getitem__(self, key):
+ return "getitem=%s" % dict.__getitem__(self, key)
+
+ def get(self, key, default=None):
+ return "get=%s" % dict.get(self, key, 'default=%r' % default)
+
+ custom = customdict({'key': 'value'})
+ view = self.mappingproxy(custom)
+ self.assertTrue('key' in view)
+ self.assertTrue('magic' in view)
+ self.assertFalse('xxx' in view)
+ self.assertEqual(view['key'], 'getitem=value')
+ self.assertRaises(KeyError, view.__getitem__, 'xxx')
+ self.assertEqual(tuple(view), ('iter',))
+ self.assertEqual(len(view), 500)
+ self.assertEqual(view.copy(), 'copy')
+ self.assertEqual(view.get('key'), 'get=value')
+ self.assertEqual(view.get('xxx'), 'get=default=None')
+ self.assertEqual(view.items(), 'items')
+ self.assertEqual(view.keys(), 'keys')
+ self.assertEqual(view.values(), 'values')
+
+ def test_chainmap(self):
+ d1 = {'x': 1}
+ d2 = {'y': 2}
+ mapping = collections.ChainMap(d1, d2)
+ view = self.mappingproxy(mapping)
+ self.assertTrue('x' in view)
+ self.assertTrue('y' in view)
+ self.assertFalse('z' in view)
+ self.assertEqual(view['x'], 1)
+ self.assertEqual(view['y'], 2)
+ self.assertRaises(KeyError, view.__getitem__, 'z')
+ self.assertEqual(tuple(sorted(view)), ('x', 'y'))
+ self.assertEqual(len(view), 2)
+ copy = view.copy()
+ self.assertIsNot(copy, mapping)
+ self.assertIsInstance(copy, collections.ChainMap)
+ self.assertEqual(copy, mapping)
+ self.assertEqual(view.get('x'), 1)
+ self.assertEqual(view.get('y'), 2)
+ self.assertIsNone(view.get('z'))
+ self.assertEqual(tuple(sorted(view.items())), (('x', 1), ('y', 2)))
+ self.assertEqual(tuple(sorted(view.keys())), ('x', 'y'))
+ self.assertEqual(tuple(sorted(view.values())), (1, 2))
+
+ def test_contains(self):
+ view = self.mappingproxy(dict.fromkeys('abc'))
+ self.assertTrue('a' in view)
+ self.assertTrue('b' in view)
+ self.assertTrue('c' in view)
+ self.assertFalse('xxx' in view)
+
+ def test_views(self):
+ mapping = {}
+ view = self.mappingproxy(mapping)
+ keys = view.keys()
+ values = view.values()
+ items = view.items()
+ self.assertEqual(list(keys), [])
+ self.assertEqual(list(values), [])
+ self.assertEqual(list(items), [])
+ mapping['key'] = 'value'
+ self.assertEqual(list(keys), ['key'])
+ self.assertEqual(list(values), ['value'])
+ self.assertEqual(list(items), [('key', 'value')])
+
+ def test_len(self):
+ for expected in range(6):
+ data = dict.fromkeys('abcde'[:expected])
+ self.assertEqual(len(data), expected)
+ view = self.mappingproxy(data)
+ self.assertEqual(len(view), expected)
+
+ def test_iterators(self):
+ keys = ('x', 'y')
+ values = (1, 2)
+ items = tuple(zip(keys, values))
+ view = self.mappingproxy(dict(items))
+ self.assertEqual(set(view), set(keys))
+ self.assertEqual(set(view.keys()), set(keys))
+ self.assertEqual(set(view.values()), set(values))
+ self.assertEqual(set(view.items()), set(items))
+
+ def test_copy(self):
+ original = {'key1': 27, 'key2': 51, 'key3': 93}
+ view = self.mappingproxy(original)
+ copy = view.copy()
+ self.assertEqual(type(copy), dict)
+ self.assertEqual(copy, original)
+ original['key1'] = 70
+ self.assertEqual(view['key1'], 70)
+ self.assertEqual(copy['key1'], 27)
+
+
def test_main():
- run_unittest(TypesTests)
+ run_unittest(TypesTests, MappingProxyTests)

if __name__ == '__main__':
test_main()
diff --git a/Lib/types.py b/Lib/types.py
--- a/Lib/types.py
+++ b/Lib/types.py
@@ -12,6 +12,7 @@
FunctionType = type(_f)
LambdaType = type(lambda: None) # Same as FunctionType
CodeType = type(_f.__code__)
+MappingProxyType = type(type.__dict__)

def _g():
yield 1
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -32,6 +32,8 @@
Library
-------

+- Issue #14386: Expose the dict_proxy internal type as types.MappingProxyType.
+
- Issue #13959: Make imp.reload() always use a module's __loader__ to perform
the reload.

diff --git a/Objects/descrobject.c b/Objects/descrobject.c
--- a/Objects/descrobject.c
+++ b/Objects/descrobject.c
@@ -698,41 +698,44 @@
}


-/* --- Readonly proxy for dictionaries (actually any mapping) --- */
+/* --- mappingproxy: read-only proxy for mappings --- */

/* This has no reason to be in this file except that adding new files is a
bit of a pain */

typedef struct {
PyObject_HEAD
- PyObject *dict;
-} proxyobject;
+ PyObject *mapping;
+} mappingproxyobject;

static Py_ssize_t
-proxy_len(proxyobject *pp)
+mappingproxy_len(mappingproxyobject *pp)
{
- return PyObject_Size(pp->dict);
+ return PyObject_Size(pp->mapping);
}

static PyObject *
-proxy_getitem(proxyobject *pp, PyObject *key)
+mappingproxy_getitem(mappingproxyobject *pp, PyObject *key)
{
- return PyObject_GetItem(pp->dict, key);
+ return PyObject_GetItem(pp->mapping, key);
}

-static PyMappingMethods proxy_as_mapping = {
- (lenfunc)proxy_len, /* mp_length */
- (binaryfunc)proxy_getitem, /* mp_subscript */
+static PyMappingMethods mappingproxy_as_mapping = {
+ (lenfunc)mappingproxy_len, /* mp_length */
+ (binaryfunc)mappingproxy_getitem, /* mp_subscript */
0, /* mp_ass_subscript */
};

static int
-proxy_contains(proxyobject *pp, PyObject *key)
+mappingproxy_contains(mappingproxyobject *pp, PyObject *key)
{
- return PyDict_Contains(pp->dict, key);
+ if (PyDict_CheckExact(pp->mapping))
+ return PyDict_Contains(pp->mapping, key);
+ else
+ return PySequence_Contains(pp->mapping, key);
}

-static PySequenceMethods proxy_as_sequence = {
+static PySequenceMethods mappingproxy_as_sequence = {
0, /* sq_length */
0, /* sq_concat */
0, /* sq_repeat */
@@ -740,152 +743,199 @@
0, /* sq_slice */
0, /* sq_ass_item */
0, /* sq_ass_slice */
- (objobjproc)proxy_contains, /* sq_contains */
+ (objobjproc)mappingproxy_contains, /* sq_contains */
0, /* sq_inplace_concat */
0, /* sq_inplace_repeat */
};

static PyObject *
-proxy_get(proxyobject *pp, PyObject *args)
+mappingproxy_get(mappingproxyobject *pp, PyObject *args)
{
PyObject *key, *def = Py_None;
_Py_IDENTIFIER(get);

if (!PyArg_UnpackTuple(args, "get", 1, 2, &key, &def))
return NULL;
- return _PyObject_CallMethodId(pp->dict, &PyId_get, "(OO)", key, def);
+ return _PyObject_CallMethodId(pp->mapping, &PyId_get, "(OO)", key, def);
}

static PyObject *
-proxy_keys(proxyobject *pp)
+mappingproxy_keys(mappingproxyobject *pp)
{
_Py_IDENTIFIER(keys);
- return _PyObject_CallMethodId(pp->dict, &PyId_keys, NULL);
+ return _PyObject_CallMethodId(pp->mapping, &PyId_keys, NULL);
}

static PyObject *
-proxy_values(proxyobject *pp)
+mappingproxy_values(mappingproxyobject *pp)
{
_Py_IDENTIFIER(values);
- return _PyObject_CallMethodId(pp->dict, &PyId_values, NULL);
+ return _PyObject_CallMethodId(pp->mapping, &PyId_values, NULL);
}

static PyObject *
-proxy_items(proxyobject *pp)
+mappingproxy_items(mappingproxyobject *pp)
{
_Py_IDENTIFIER(items);
- return _PyObject_CallMethodId(pp->dict, &PyId_items, NULL);
+ return _PyObject_CallMethodId(pp->mapping, &PyId_items, NULL);
}

static PyObject *
-proxy_copy(proxyobject *pp)
+mappingproxy_copy(mappingproxyobject *pp)
{
_Py_IDENTIFIER(copy);
- return _PyObject_CallMethodId(pp->dict, &PyId_copy, NULL);
+ return _PyObject_CallMethodId(pp->mapping, &PyId_copy, NULL);
}

-static PyMethodDef proxy_methods[] = {
- {"get", (PyCFunction)proxy_get, METH_VARARGS,
+/* WARNING: mappingproxy methods must not give access
+ to the underlying mapping */
+
+static PyMethodDef mappingproxy_methods[] = {
+ {"get", (PyCFunction)mappingproxy_get, METH_VARARGS,
PyDoc_STR("D.get(k[,d]) -> D[k] if k in D, else d."
- " d defaults to None.")},
- {"keys", (PyCFunction)proxy_keys, METH_NOARGS,
+ " d defaults to None.")},
+ {"keys", (PyCFunction)mappingproxy_keys, METH_NOARGS,
PyDoc_STR("D.keys() -> list of D's keys")},
- {"values", (PyCFunction)proxy_values, METH_NOARGS,
+ {"values", (PyCFunction)mappingproxy_values, METH_NOARGS,
PyDoc_STR("D.values() -> list of D's values")},
- {"items", (PyCFunction)proxy_items, METH_NOARGS,
+ {"items", (PyCFunction)mappingproxy_items, METH_NOARGS,
PyDoc_STR("D.items() -> list of D's (key, value) pairs, as 2-tuples")},
- {"copy", (PyCFunction)proxy_copy, METH_NOARGS,
+ {"copy", (PyCFunction)mappingproxy_copy, METH_NOARGS,
PyDoc_STR("D.copy() -> a shallow copy of D")},
{0}
};

static void
-proxy_dealloc(proxyobject *pp)
+mappingproxy_dealloc(mappingproxyobject *pp)
{
_PyObject_GC_UNTRACK(pp);
- Py_DECREF(pp->dict);
+ Py_DECREF(pp->mapping);
PyObject_GC_Del(pp);
}

static PyObject *
-proxy_getiter(proxyobject *pp)
+mappingproxy_getiter(mappingproxyobject *pp)
{
- return PyObject_GetIter(pp->dict);
+ return PyObject_GetIter(pp->mapping);
}

static PyObject *
-proxy_str(proxyobject *pp)
+mappingproxy_str(mappingproxyobject *pp)
{
- return PyObject_Str(pp->dict);
+ return PyObject_Str(pp->mapping);
}

static PyObject *
-proxy_repr(proxyobject *pp)
+mappingproxy_repr(mappingproxyobject *pp)
{
- return PyUnicode_FromFormat("dict_proxy(%R)", pp->dict);
+ return PyUnicode_FromFormat("mappingproxy(%R)", pp->mapping);
}

static int
-proxy_traverse(PyObject *self, visitproc visit, void *arg)
+mappingproxy_traverse(PyObject *self, visitproc visit, void *arg)
{
- proxyobject *pp = (proxyobject *)self;
- Py_VISIT(pp->dict);
+ mappingproxyobject *pp = (mappingproxyobject *)self;
+ Py_VISIT(pp->mapping);
return 0;
}

static PyObject *
-proxy_richcompare(proxyobject *v, PyObject *w, int op)
+mappingproxy_richcompare(mappingproxyobject *v, PyObject *w, int op)
{
- return PyObject_RichCompare(v->dict, w, op);
+ return PyObject_RichCompare(v->mapping, w, op);
+}
+
+static int
+mappingproxy_check_mapping(PyObject *mapping)
+{
+ if (!PyMapping_Check(mapping)
+ || PyList_Check(mapping)
+ || PyTuple_Check(mapping)) {
+ PyErr_Format(PyExc_TypeError,
+ "mappingproxy() argument must be a mapping, not %s",
+ Py_TYPE(mapping)->tp_name);
+ return -1;
+ }
+ return 0;
+}
+
+static PyObject*
+mappingproxy_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"mapping", NULL};
+ PyObject *mapping;
+ mappingproxyobject *mappingproxy;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:mappingproxy",
+ kwlist, &mapping))
+ return NULL;
+
+ if (mappingproxy_check_mapping(mapping) == -1)
+ return NULL;
+
+ mappingproxy = PyObject_GC_New(mappingproxyobject, &PyDictProxy_Type);
+ if (mappingproxy == NULL)
+ return NULL;
+ Py_INCREF(mapping);
+ mappingproxy->mapping = mapping;
+ _PyObject_GC_TRACK(mappingproxy);
+ return (PyObject *)mappingproxy;
}

PyTypeObject PyDictProxy_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
- "dict_proxy", /* tp_name */
- sizeof(proxyobject), /* tp_basicsize */
+ "mappingproxy", /* tp_name */
+ sizeof(mappingproxyobject), /* tp_basicsize */
0, /* tp_itemsize */
/* methods */
- (destructor)proxy_dealloc, /* tp_dealloc */
+ (destructor)mappingproxy_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_reserved */
- (reprfunc)proxy_repr, /* tp_repr */
+ (reprfunc)mappingproxy_repr, /* tp_repr */
0, /* tp_as_number */
- &proxy_as_sequence, /* tp_as_sequence */
- &proxy_as_mapping, /* tp_as_mapping */
+ &mappingproxy_as_sequence, /* tp_as_sequence */
+ &mappingproxy_as_mapping, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
- (reprfunc)proxy_str, /* tp_str */
+ (reprfunc)mappingproxy_str, /* tp_str */
PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
0, /* tp_doc */
- proxy_traverse, /* tp_traverse */
+ mappingproxy_traverse, /* tp_traverse */
0, /* tp_clear */
- (richcmpfunc)proxy_richcompare, /* tp_richcompare */
+ (richcmpfunc)mappingproxy_richcompare, /* tp_richcompare */
0, /* tp_weaklistoffset */
- (getiterfunc)proxy_getiter, /* tp_iter */
+ (getiterfunc)mappingproxy_getiter, /* tp_iter */
0, /* tp_iternext */
- proxy_methods, /* tp_methods */
+ mappingproxy_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ mappingproxy_new, /* tp_new */
};

PyObject *
-PyDictProxy_New(PyObject *dict)
+PyDictProxy_New(PyObject *mapping)
{
- proxyobject *pp;
+ mappingproxyobject *pp;

- pp = PyObject_GC_New(proxyobject, &PyDictProxy_Type);
+ if (mappingproxy_check_mapping(mapping) == -1)
+ return NULL;
+
+ pp = PyObject_GC_New(mappingproxyobject, &PyDictProxy_Type);
if (pp != NULL) {
- Py_INCREF(dict);
- pp->dict = dict;
+ Py_INCREF(mapping);
+ pp->mapping = mapping;
_PyObject_GC_TRACK(pp);
}
return (PyObject *)pp;

--
Repository URL: http://hg.python.org/cpython
cpython (merge default -> default): merge [ In reply to ]
http://hg.python.org/cpython/rev/d72932e80130
changeset: 76343:d72932e80130
parent: 76342:4256df44023b
parent: 76340:34f09c654a5b
user: Brett Cannon <brett@python.org>
date: Sun Apr 15 22:28:45 2012 -0400
summary:
merge

files:
Lib/test/sha256.pem | 231 ++++++++++++++++---------------
Misc/NEWS | 3 +
2 files changed, 119 insertions(+), 115 deletions(-)


diff --git a/Lib/test/sha256.pem b/Lib/test/sha256.pem
--- a/Lib/test/sha256.pem
+++ b/Lib/test/sha256.pem
@@ -1,129 +1,128 @@
# Certificate chain for https://sha256.tbs-internet.com
- 0 s:/C=FR/postalCode=14000/ST=Calvados/L=CAEN/street=22 rue de Bretagne/O=TBS INTERNET/OU=0002 440443810/OU=sha-256 production/CN=sha256.tbs-internet.com
- i:/C=FR/ST=Calvados/L=Caen/O=TBS INTERNET/OU=Terms and Conditions: http://www.tbs-internet.com/CA/repository/OU=TBS INTERNET CA/CN=TBS X509 CA SGC
+ 0 s:/C=FR/postalCode=14000/ST=Calvados/L=CAEN/street=22 rue de Bretagne/O=TBS INTERNET/OU=0002 440443810/OU=Certificats TBS X509/CN=ecom.tbs-x509.com
+ i:/C=FR/ST=Calvados/L=Caen/O=TBS INTERNET/OU=Terms and Conditions: http://www.tbs-internet.com/CA/repository/OU=TBS INTERNET CA/CN=TBS X509 CA business
-----BEGIN CERTIFICATE-----
-MIIGXTCCBUWgAwIBAgIRAMmag+ygSAdxZsbyzYjhuW0wDQYJKoZIhvcNAQELBQAw
-gcQxCzAJBgNVBAYTAkZSMREwDwYDVQQIEwhDYWx2YWRvczENMAsGA1UEBxMEQ2Fl
+MIIGTjCCBTagAwIBAgIQOh3d9dNDPq1cSdJmEiMpqDANBgkqhkiG9w0BAQUFADCB
+yTELMAkGA1UEBhMCRlIxETAPBgNVBAgTCENhbHZhZG9zMQ0wCwYDVQQHEwRDYWVu
+MRUwEwYDVQQKEwxUQlMgSU5URVJORVQxSDBGBgNVBAsTP1Rlcm1zIGFuZCBDb25k
+aXRpb25zOiBodHRwOi8vd3d3LnRicy1pbnRlcm5ldC5jb20vQ0EvcmVwb3NpdG9y
+eTEYMBYGA1UECxMPVEJTIElOVEVSTkVUIENBMR0wGwYDVQQDExRUQlMgWDUwOSBD
+QSBidXNpbmVzczAeFw0xMTAxMjUwMDAwMDBaFw0xMzAyMDUyMzU5NTlaMIHHMQsw
+CQYDVQQGEwJGUjEOMAwGA1UEERMFMTQwMDAxETAPBgNVBAgTCENhbHZhZG9zMQ0w
+CwYDVQQHEwRDQUVOMRswGQYDVQQJExIyMiBydWUgZGUgQnJldGFnbmUxFTATBgNV
+BAoTDFRCUyBJTlRFUk5FVDEXMBUGA1UECxMOMDAwMiA0NDA0NDM4MTAxHTAbBgNV
+BAsTFENlcnRpZmljYXRzIFRCUyBYNTA5MRowGAYDVQQDExFlY29tLnRicy14NTA5
+LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKRrlHUnJ++1lpcg
+jtYco7cdmRe+EEfTmwPfCdfV3G1QfsTSvY6FfMpm/83pqHfT+4ANwr18wD9ZrAEN
+G16mf9VdCGK12+TP7DmqeZyGIqlFFoahQnmb8EarvE43/1UeQ2CV9XmzwZvpqeli
+LfXsFonawrY3H6ZnMwS64St61Z+9gdyuZ/RbsoZBbT5KUjDEG844QRU4OT1IGeEI
+eY5NM5RNIh6ZNhVtqeeCxMS7afONkHQrOco73RdSTRck/Hj96Ofl3MHNHryr+AMK
+DGFk1kLCZGpPdXtkxXvaDeQoiYDlil26CWc+YK6xyDPMdsWvoG14ZLyCpzMXA7/7
+4YAQRH0CAwEAAaOCAjAwggIsMB8GA1UdIwQYMBaAFBoJBMz5CY+7HqDO1KQUf0vV
+I1jNMB0GA1UdDgQWBBQgOU8HsWzbmD4WZP5Wtdw7jca2WDAOBgNVHQ8BAf8EBAMC
+BaAwDAYDVR0TAQH/BAIwADAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw
+TAYDVR0gBEUwQzBBBgsrBgEEAYDlNwIBATAyMDAGCCsGAQUFBwIBFiRodHRwczov
+L3d3dy50YnMtaW50ZXJuZXQuY29tL0NBL0NQUzEwdwYDVR0fBHAwbjA3oDWgM4Yx
+aHR0cDovL2NybC50YnMtaW50ZXJuZXQuY29tL1RCU1g1MDlDQWJ1c2luZXNzLmNy
+bDAzoDGgL4YtaHR0cDovL2NybC50YnMteDUwOS5jb20vVEJTWDUwOUNBYnVzaW5l
+c3MuY3JsMIGwBggrBgEFBQcBAQSBozCBoDA9BggrBgEFBQcwAoYxaHR0cDovL2Ny
+dC50YnMtaW50ZXJuZXQuY29tL1RCU1g1MDlDQWJ1c2luZXNzLmNydDA5BggrBgEF
+BQcwAoYtaHR0cDovL2NydC50YnMteDUwOS5jb20vVEJTWDUwOUNBYnVzaW5lc3Mu
+Y3J0MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC50YnMteDUwOS5jb20wMwYDVR0R
+BCwwKoIRZWNvbS50YnMteDUwOS5jb22CFXd3dy5lY29tLnRicy14NTA5LmNvbTAN
+BgkqhkiG9w0BAQUFAAOCAQEArT4NHfbY87bGAw8lPV4DmHlmuDuVp/y7ltO3Ynse
+3Rz8RxW2AzuO0Oy2F0Cu4yWKtMyEyMXyHqWtae7ElRbdTu5w5GwVBLJHClCzC8S9
+SpgMMQTx3Rgn8vjkHuU9VZQlulZyiPK7yunjc7c310S9FRZ7XxOwf8Nnx4WnB+No
+WrfApzhhQl31w+RyrNxZe58hCfDDHmevRvwLjQ785ZoQXJDj2j3qAD4aI2yB8lB5
+oaE1jlCJzC7Kmz/Y9jzfmv/zAs1LQTm9ktevv4BTUFaGjv9jxnQ1xnS862ZiouLW
+zZYIlYPf4F6JjXGiIQgQRglILUfq3ftJd9/ok9W9ZF8h8w==
+-----END CERTIFICATE-----
+ 1 s:/C=FR/ST=Calvados/L=Caen/O=TBS INTERNET/OU=Terms and Conditions: http://www.tbs-internet.com/CA/repository/OU=TBS INTERNET CA/CN=TBS X509 CA business
+ i:/C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root
+-----BEGIN CERTIFICATE-----
+MIIFPzCCBCegAwIBAgIQDlBz/++iRSmLDeVRHT/hADANBgkqhkiG9w0BAQUFADBv
+MQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFk
+ZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBF
+eHRlcm5hbCBDQSBSb290MB4XDTA1MTIwMTAwMDAwMFoXDTE5MDcwOTE4MTkyMlow
+gckxCzAJBgNVBAYTAkZSMREwDwYDVQQIEwhDYWx2YWRvczENMAsGA1UEBxMEQ2Fl
bjEVMBMGA1UEChMMVEJTIElOVEVSTkVUMUgwRgYDVQQLEz9UZXJtcyBhbmQgQ29u
ZGl0aW9uczogaHR0cDovL3d3dy50YnMtaW50ZXJuZXQuY29tL0NBL3JlcG9zaXRv
-cnkxGDAWBgNVBAsTD1RCUyBJTlRFUk5FVCBDQTEYMBYGA1UEAxMPVEJTIFg1MDkg
-Q0EgU0dDMB4XDTEwMDIxODAwMDAwMFoXDTEyMDIxOTIzNTk1OVowgcsxCzAJBgNV
-BAYTAkZSMQ4wDAYDVQQREwUxNDAwMDERMA8GA1UECBMIQ2FsdmFkb3MxDTALBgNV
-BAcTBENBRU4xGzAZBgNVBAkTEjIyIHJ1ZSBkZSBCcmV0YWduZTEVMBMGA1UEChMM
-VEJTIElOVEVSTkVUMRcwFQYDVQQLEw4wMDAyIDQ0MDQ0MzgxMDEbMBkGA1UECxMS
-c2hhLTI1NiBwcm9kdWN0aW9uMSAwHgYDVQQDExdzaGEyNTYudGJzLWludGVybmV0
-LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKbuM8VT7f0nntwu
-N3F7v9KIBlhKNAxqCrziOXU5iqUt8HrQB3DtHbdmII+CpVUlwlmepsx6G+srEZ9a
-MIGAy0nxi5aLb7watkyIdPjJTMvTUBQ/+RPWzt5JtYbbY9BlJ+yci0dctP74f4NU
-ISLtlrEjUbf2gTohLrcE01TfmOF6PDEbB5PKDi38cB3NzKfizWfrOaJW6Q1C1qOJ
-y4/4jkUREX1UFUIxzx7v62VfjXSGlcjGpBX1fvtABQOSLeE0a6gciDZs1REqroFf
-5eXtqYphpTa14Z83ITXMfgg5Nze1VtMnzI9Qx4blYBw4dgQVEuIsYr7FDBOITDzc
-VEVXZx0CAwEAAaOCAj8wggI7MB8GA1UdIwQYMBaAFAdEdoWTKLx/bXjSCuv6TEvf
-2YIfMB0GA1UdDgQWBBSJKI/AYVI9RQNY0QPIqc8ej2QivTAOBgNVHQ8BAf8EBAMC
-BaAwDAYDVR0TAQH/BAIwADA0BgNVHSUELTArBggrBgEFBQcDAQYIKwYBBQUHAwIG
-CisGAQQBgjcKAwMGCWCGSAGG+EIEATBMBgNVHSAERTBDMEEGCysGAQQBgOU3AgQB
-MDIwMAYIKwYBBQUHAgEWJGh0dHBzOi8vd3d3LnRicy1pbnRlcm5ldC5jb20vQ0Ev
-Q1BTNDBtBgNVHR8EZjBkMDKgMKAuhixodHRwOi8vY3JsLnRicy1pbnRlcm5ldC5j
-b20vVEJTWDUwOUNBU0dDLmNybDAuoCygKoYoaHR0cDovL2NybC50YnMteDUwOS5j
-b20vVEJTWDUwOUNBU0dDLmNybDCBpgYIKwYBBQUHAQEEgZkwgZYwOAYIKwYBBQUH
-MAKGLGh0dHA6Ly9jcnQudGJzLWludGVybmV0LmNvbS9UQlNYNTA5Q0FTR0MuY3J0
-MDQGCCsGAQUFBzAChihodHRwOi8vY3J0LnRicy14NTA5LmNvbS9UQlNYNTA5Q0FT
-R0MuY3J0MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC50YnMteDUwOS5jb20wPwYD
-VR0RBDgwNoIXc2hhMjU2LnRicy1pbnRlcm5ldC5jb22CG3d3dy5zaGEyNTYudGJz
-LWludGVybmV0LmNvbTANBgkqhkiG9w0BAQsFAAOCAQEAA5NL0D4QSqhErhlkdPmz
-XtiMvdGL+ZehM4coTRIpasM/Agt36Rc0NzCvnQwKE+wkngg1Gy2qe7Q0E/ziqBtB
-fZYzdVgu1zdiL4kTaf+wFKYAFGsFbyeEmXysy+CMwaNoF2vpSjCU1UD56bEnTX/W
-fxVZYxtBQUpnu2wOsm8cDZuZRv9XrYgAhGj9Tt6F0aVHSDGn59uwShG1+BVF/uju
-SCyPTTjL1oc7YElJUzR/x4mQJYvtQI8gDIDAGEOs7v3R/gKa5EMfbUQUI4C84UbI
-Yz09Jdnws/MkC/Hm1BZEqk89u7Hvfv+oHqEb0XaUo0TDfsxE0M1sMdnLb91QNQBm
-UQ==
------END CERTIFICATE-----
- 1 s:/C=FR/ST=Calvados/L=Caen/O=TBS INTERNET/OU=Terms and Conditions: http://www.tbs-internet.com/CA/repository/OU=TBS INTERNET CA/CN=TBS X509 CA SGC
- i:/C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root
------BEGIN CERTIFICATE-----
-MIIFVjCCBD6gAwIBAgIQXpDZ0ETJMV02WTx3GTnhhTANBgkqhkiG9w0BAQUFADBv
-MQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFk
-ZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBF
-eHRlcm5hbCBDQSBSb290MB4XDTA1MTIwMTAwMDAwMFoXDTE5MDYyNDE5MDYzMFow
-gcQxCzAJBgNVBAYTAkZSMREwDwYDVQQIEwhDYWx2YWRvczENMAsGA1UEBxMEQ2Fl
-bjEVMBMGA1UEChMMVEJTIElOVEVSTkVUMUgwRgYDVQQLEz9UZXJtcyBhbmQgQ29u
-ZGl0aW9uczogaHR0cDovL3d3dy50YnMtaW50ZXJuZXQuY29tL0NBL3JlcG9zaXRv
-cnkxGDAWBgNVBAsTD1RCUyBJTlRFUk5FVCBDQTEYMBYGA1UEAxMPVEJTIFg1MDkg
-Q0EgU0dDMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsgOkO3f7wzN6
-rOjg45tR5vjBfzK7qmV9IBxb/QW9EEXxG+E7FNhZqQLtwGBKoSsHTnQqV75wWMk0
-9tinWvftBkSpj5sTi/8cbzJfUvTSVYh3Qxv6AVVjMMH/ruLjE6y+4PoaPs8WoYAQ
-ts5R4Z1g8c/WnTepLst2x0/Wv7GmuoQi+gXvHU6YrBiu7XkeYhzc95QdviWSJRDk
-owhb5K43qhcvjRmBfO/paGlCliDGZp8mHwrI21mwobWpVjTxZRwYO3bd4+TGcI4G
-Ie5wmHwE8F7SK1tgSqbBacKjDa93j7txKkfz/Yd2n7TGqOXiHPsJpG655vrKtnXk
-9vs1zoDeJQIDAQABo4IBljCCAZIwHQYDVR0OBBYEFAdEdoWTKLx/bXjSCuv6TEvf
-2YIfMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMCAGA1UdJQQZ
-MBcGCisGAQQBgjcKAwMGCWCGSAGG+EIEATAYBgNVHSAEETAPMA0GCysGAQQBgOU3
-AgQBMHsGA1UdHwR0MHIwOKA2oDSGMmh0dHA6Ly9jcmwuY29tb2RvY2EuY29tL0Fk
-ZFRydXN0RXh0ZXJuYWxDQVJvb3QuY3JsMDagNKAyhjBodHRwOi8vY3JsLmNvbW9k
-by5uZXQvQWRkVHJ1c3RFeHRlcm5hbENBUm9vdC5jcmwwgYAGCCsGAQUFBwEBBHQw
-cjA4BggrBgEFBQcwAoYsaHR0cDovL2NydC5jb21vZG9jYS5jb20vQWRkVHJ1c3RV
-VE5TR0NDQS5jcnQwNgYIKwYBBQUHMAKGKmh0dHA6Ly9jcnQuY29tb2RvLm5ldC9B
-ZGRUcnVzdFVUTlNHQ0NBLmNydDARBglghkgBhvhCAQEEBAMCAgQwDQYJKoZIhvcN
-AQEFBQADggEBAK2zEzs+jcIrVK9oDkdDZNvhuBYTdCfpxfFs+OAujW0bIfJAy232
-euVsnJm6u/+OrqKudD2tad2BbejLLXhMZViaCmK7D9nrXHx4te5EP8rL19SUVqLY
-1pTnv5dhNgEgvA7n5lIzDSYs7yRLsr7HJsYPr6SeYSuZizyX1SNz7ooJ32/F3X98
-RB0Mlc/E0OyOrkQ9/y5IrnpnaSora8CnUrV5XNOg+kyCz9edCyx4D5wXYcwZPVWz
-8aDqquESrezPyjtfi4WRO4s/VD3HLZvOxzMrWAVYCDG9FxaOhF0QGuuG1F7F3GKV
-v6prNyCl016kRl2j1UT+a7gLd8fA25A4C9E=
+cnkxGDAWBgNVBAsTD1RCUyBJTlRFUk5FVCBDQTEdMBsGA1UEAxMUVEJTIFg1MDkg
+Q0EgYnVzaW5lc3MwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDB1PAU
+qudCcz3tmyGcf+u6EkZqonKKHrV4gZYbvVkIRojmmlhfi/jwvpHvo8bqSt/9Rj5S
+jhCDW0pcbI+IPPtD1Jy+CHNSfnMqVDy6CKQ3p5maTzCMG6ZT+XjnvcND5v+FtaiB
+xk1iCX6uvt0jeUtdZvYbyytsSDE6c3Y5//wRxOF8tM1JxibwO3pyER26jbbN2gQz
+m/EkdGjLdJ4svPk23WDAvQ6G0/z2LcAaJB+XLfqRwfQpHQvfKa1uTi8PivC8qtip
+rmNQMMPMjxSK2azX8cKjjTDJiUKaCb4VHlJDWKEsCFRpgJAoAuX8f7Yfs1M4esGo
+sWb3PGspK3O22uIlAgMBAAGjggF6MIIBdjAdBgNVHQ4EFgQUGgkEzPkJj7seoM7U
+pBR/S9UjWM0wDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwGAYD
+VR0gBBEwDzANBgsrBgEEAYDlNwIBATB7BgNVHR8EdDByMDigNqA0hjJodHRwOi8v
+Y3JsLmNvbW9kb2NhLmNvbS9BZGRUcnVzdEV4dGVybmFsQ0FSb290LmNybDA2oDSg
+MoYwaHR0cDovL2NybC5jb21vZG8ubmV0L0FkZFRydXN0RXh0ZXJuYWxDQVJvb3Qu
+Y3JsMIGGBggrBgEFBQcBAQR6MHgwOwYIKwYBBQUHMAKGL2h0dHA6Ly9jcnQuY29t
+b2RvY2EuY29tL0FkZFRydXN0VVROU2VydmVyQ0EuY3J0MDkGCCsGAQUFBzAChi1o
+dHRwOi8vY3J0LmNvbW9kby5uZXQvQWRkVHJ1c3RVVE5TZXJ2ZXJDQS5jcnQwEQYJ
+YIZIAYb4QgEBBAQDAgIEMA0GCSqGSIb3DQEBBQUAA4IBAQA7mqrMgk/MrE6QnbNA
+h4nRCn2ti4bg4w2C3lB6bSvRPnYwuNw9Jb8vuKkNFzRDxNJXqVDZdfFW5CVQJuyd
+nfAx83+wk+spzvFaE1KhFYfN9G9pQfXUfvDRoIcJgPEKUXL1wRiOG+IjU3VVI8pg
+IgqHkr7ylln5i5zCiFAPuIJmYUSFg/gxH5xkCNcjJqqrHrHatJr6Qrrke93joupw
+oU1njfAcZtYp6fbiK6u2b1pJqwkVBE8RsfLnPhRj+SFbpvjv8Od7o/ieJhFIYQNU
+k2jX2u8qZnAiNw93LZW9lpYjtuvMXq8QQppENNja5b53q7UwI+lU7ZGjZ7quuESp
+J6/5
-----END CERTIFICATE-----
2 s:/C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root
- i:/C=US/ST=UT/L=Salt Lake City/O=The USERTRUST Network/OU=http://www.usertrust.com/CN=UTN - DATACorp SGC
+ i:/C=US/ST=UT/L=Salt Lake City/O=The USERTRUST Network/OU=http://www.usertrust.com/CN=UTN-USERFirst-Hardware
-----BEGIN CERTIFICATE-----
-MIIEZjCCA06gAwIBAgIQUSYKkxzif5zDpV954HKugjANBgkqhkiG9w0BAQUFADCB
-kzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
+MIIETzCCAzegAwIBAgIQHM5EYpUZep1jUvnyI6m2mDANBgkqhkiG9w0BAQUFADCB
+lzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho
-dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xGzAZBgNVBAMTElVUTiAtIERBVEFDb3Jw
-IFNHQzAeFw0wNTA2MDcwODA5MTBaFw0xOTA2MjQxOTA2MzBaMG8xCzAJBgNVBAYT
-AlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0
-ZXJuYWwgVFRQIE5ldHdvcmsxIjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENB
-IFJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC39xoz5vIABC05
-4E5b7R+8bA/Ntfojts7emxEzl6QpTH2Tn71KvJPtAxrjj8/lbVBa1pcplFqAsEl6
-2y6V/bjKvzc4LR4+kUGtcFbH8E8/6DKedMrIkFTpxl8PeJ2aQDwOrGGqXhSPnoeh
-alDc15pOrwWzpnGUnHGzUGAKxxOdOAeGAqjpqGkmGJCrTLBPI6s6T4TY386f4Wlv
-u9dC12tE5Met7m1BX3JacQg3s3llpFmglDf3AC8NwpJy2tA4ctsUqEXEXSp9t7TW
-xO6szRNEt8kr3UMAJfphuWlqWCMRt6czj1Z1WfXNKddGtworZbbTQm8Vsrh7++/p
-XVPVNFonAgMBAAGjgdgwgdUwHwYDVR0jBBgwFoAUUzLRs89/+uDxoF2FTpLSnkUd
-tE8wHQYDVR0OBBYEFK29mHo0tCb3+sQmVO8DveAky1QaMA4GA1UdDwEB/wQEAwIB
-BjAPBgNVHRMBAf8EBTADAQH/MBEGCWCGSAGG+EIBAQQEAwIBAjAgBgNVHSUEGTAX
-BgorBgEEAYI3CgMDBglghkgBhvhCBAEwPQYDVR0fBDYwNDAyoDCgLoYsaHR0cDov
-L2NybC51c2VydHJ1c3QuY29tL1VUTi1EQVRBQ29ycFNHQy5jcmwwDQYJKoZIhvcN
-AQEFBQADggEBAMbuUxdoFLJRIh6QWA2U/b3xcOWGLcM2MY9USEbnLQg3vGwKYOEO
-rVE04BKT6b64q7gmtOmWPSiPrmQH/uAB7MXjkesYoPF1ftsK5p+R26+udd8jkWjd
-FwBaS/9kbHDrARrQkNnHptZt9hPk/7XJ0h4qy7ElQyZ42TCbTg0evmnv3+r+LbPM
-+bDdtRTKkdSytaX7ARmjR3mfnYyVhzT4HziS2jamEfpr62vp3EV4FTkG101B5CHI
-3C+H0be/SGB1pWLLJN47YaApIKa+xWycxOkKaSLvkTr6Jq/RW0GnOuL4OAdCq8Fb
-+M5tug8EPzI0rNwEKNdwMBQmBsTkm5jVz3g=
+dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3Qt
+SGFyZHdhcmUwHhcNMDUwNjA3MDgwOTEwWhcNMTkwNzA5MTgxOTIyWjBvMQswCQYD
+VQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0
+IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5h
+bCBDQSBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAt/caM+by
+AAQtOeBOW+0fvGwPzbX6I7bO3psRM5ekKUx9k5+9SryT7QMa44/P5W1QWtaXKZRa
+gLBJetsulf24yr83OC0ePpFBrXBWx/BPP+gynnTKyJBU6cZfD3idmkA8Dqxhql4U
+j56HoWpQ3NeaTq8Fs6ZxlJxxs1BgCscTnTgHhgKo6ahpJhiQq0ywTyOrOk+E2N/O
+n+Fpb7vXQtdrROTHre5tQV9yWnEIN7N5ZaRZoJQ39wAvDcKSctrQOHLbFKhFxF0q
+fbe01sTurM0TRLfJK91DACX6YblpalgjEbenM49WdVn1zSnXRrcKK2W200JvFbK4
+e/vv6V1T1TRaJwIDAQABo4G9MIG6MB8GA1UdIwQYMBaAFKFyXyYbKJhDlV0HN9WF
+lp1L0sNFMB0GA1UdDgQWBBStvZh6NLQm9/rEJlTvA73gJMtUGjAOBgNVHQ8BAf8E
+BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zARBglghkgBhvhCAQEEBAMCAQIwRAYDVR0f
+BD0wOzA5oDegNYYzaHR0cDovL2NybC51c2VydHJ1c3QuY29tL1VUTi1VU0VSRmly
+c3QtSGFyZHdhcmUuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQByQhANOs4kClrwF8BW
+onvUOGCSjRK52zYZgDXYNjDtmr5rJ6NyPFDNn+JxkLpjYetIFMTbSRe679Bt8m7a
+gIAoQYFQtxMuyLnJegB2aEbQiIxh/tC21UcFF7ktdnDoTlA6w3pLuvunaI84Of3o
+2YBrhzkTbCfaYk5JRlTpudW9DkUkHBsyx3nknPKnplkIGaK0jgn8E0n+SFabYaHk
+I9LroYT/+JtLefh9lgBdAgVv0UPbzoGfuDsrk/Zh+UrgbLFpHoVnElhzbkh64Z0X
+OGaJunQc68cCZu5HTn/aK7fBGMcVflRCXLVEQpU9PIAdGA8Ynvg684t8GMaKsRl1
+jIGZ
-----END CERTIFICATE-----
- 3 s:/C=US/ST=UT/L=Salt Lake City/O=The USERTRUST Network/OU=http://www.usertrust.com/CN=UTN - DATACorp SGC
- i:/C=US/ST=UT/L=Salt Lake City/O=The USERTRUST Network/OU=http://www.usertrust.com/CN=UTN - DATACorp SGC
+ 3 s:/C=US/ST=UT/L=Salt Lake City/O=The USERTRUST Network/OU=http://www.usertrust.com/CN=UTN-USERFirst-Hardware
+ i:/C=US/ST=UT/L=Salt Lake City/O=The USERTRUST Network/OU=http://www.usertrust.com/CN=UTN-USERFirst-Hardware
-----BEGIN CERTIFICATE-----
-MIIEXjCCA0agAwIBAgIQRL4Mi1AAIbQR0ypoBqmtaTANBgkqhkiG9w0BAQUFADCB
-kzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
+MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUFADCB
+lzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho
-dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xGzAZBgNVBAMTElVUTiAtIERBVEFDb3Jw
-IFNHQzAeFw05OTA2MjQxODU3MjFaFw0xOTA2MjQxOTA2MzBaMIGTMQswCQYDVQQG
-EwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYD
-VQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cu
-dXNlcnRydXN0LmNvbTEbMBkGA1UEAxMSVVROIC0gREFUQUNvcnAgU0dDMIIBIjAN
-BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3+5YEKIrblXEjr8uRgnn4AgPLit6
-E5Qbvfa2gI5lBZMAHryv4g+OGQ0SR+ysraP6LnD43m77VkIVni5c7yPeIbkFdicZ
-D0/Ww5y0vpQZY/KmEQrrU0icvvIpOxboGqBMpsn0GFlowHDyUwDAXlCCpVZvNvlK
-4ESGoE1O1kduSUrLZ9emxAW5jh70/P/N5zbgnAVssjMiFdC04MwXwLLA9P4yPykq
-lXvY8qdOD1R8oQ2AswkDwf9c3V6aPryuvEeKaq5xyh+xKrhfQgUL7EYw0XILyulW
-bfXv33i+Ybqypa4ETLyorGkVl73v67SMvzX41MPRKA5cOp9wGDMgd8SirwIDAQAB
-o4GrMIGoMAsGA1UdDwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRT
-MtGzz3/64PGgXYVOktKeRR20TzA9BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vY3Js
-LnVzZXJ0cnVzdC5jb20vVVROLURBVEFDb3JwU0dDLmNybDAqBgNVHSUEIzAhBggr
-BgEFBQcDAQYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBMA0GCSqGSIb3DQEBBQUAA4IB
-AQAnNZcAiosovcYzMB4p/OL31ZjUQLtgyr+rFywJNn9Q+kHcrpY6CiM+iVnJowft
-Gzet/Hy+UUla3joKVAgWRcKZsYfNjGjgaQPpxE6YsjuMFrMOoAyYUJuTqXAJyCyj
-j98C5OBxOvG0I3KgqgHf35g+FFCgMSa9KOlaMCZ1+XtgHI3zzVAmbQQnmt/VDUVH
-KWss5nbZqSl9Mt3JNjy9rjXxEZ4du5A/EkdOjtd+D2JzHVImOBwYSf0wdJrE5SIv
-2MCN7ZF6TACPcn9d2t0bi0Vr591pl6jFVkwPDPafepE39peC4N1xaf92P2BNPM/3
-mfnGV/TJVTl4uix5yaaIK/QI
+dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3Qt
+SGFyZHdhcmUwHhcNOTkwNzA5MTgxMDQyWhcNMTkwNzA5MTgxOTIyWjCBlzELMAkG
+A1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEe
+MBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8v
+d3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdh
+cmUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCx98M4P7Sof885glFn
+0G2f0v9Y8+efK+wNiVSZuTiZFvfgIXlIwrthdBKWHTxqctU8EGc6Oe0rE81m65UJ
+M6Rsl7HoxuzBdXmcRl6Nq9Bq/bkqVRcQVLMZ8Jr28bFdtqdt++BxF2uiiPsA3/4a
+MXcMmgF6sTLjKwEHOG7DpV4jvEWbe1DByTCP2+UretNb+zNAHqDVmBe8i4fDidNd
+oI6yqqr2jmmIBsX6iSHzCJ1pLgkzmykNRg+MzEk0sGlRvfkGzWitZky8PqxhvQqI
+DsjfPe58BEydCl5rkdbux+0ojatNh4lz0G6k0B4WixThdkQDf2Os5M1JnMWS9Ksy
+oUhbAgMBAAGjgbkwgbYwCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYD
+VR0OBBYEFKFyXyYbKJhDlV0HN9WFlp1L0sNFMEQGA1UdHwQ9MDswOaA3oDWGM2h0
+dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNFUkZpcnN0LUhhcmR3YXJlLmNy
+bDAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwUGCCsGAQUFBwMGBggrBgEF
+BQcDBzANBgkqhkiG9w0BAQUFAAOCAQEARxkP3nTGmZev/K0oXnWO6y1n7k57K9cM
+//bey1WiCuFMVGWTYGufEpytXoMs61quwOQt9ABjHbjAbPLPSbtNk28Gpgoiskli
+CE7/yMgUsogWXecB5BKV5UU0s4tpvc+0hY91UZ59Ojg6FEgSxvunOxqNDYJAB+gE
+CJChicsZUN/KHAG8HQQZexB2lzvukJDKxA4fFm517zP4029bHpbj4HR3dHuKom4t
+3XbWOTCC8KucUvIqx69JXn7HaOWCgchqJ/kniCrVWFCVH/A7HFe7fRQ5YiuayZSS
+KqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnASfxAynB67nfhmqA==
-----END CERTIFICATE-----
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -90,6 +90,9 @@
Tests
-----

+- Issue #14589: Update certificate chain for sha256.tbs-internet.com, fixing
+ a test failure in test_ssl.
+
- Issue #14355: Regrtest now supports the standard unittest test loading, and
will use it if a test file contains no `test_main` method.


--
Repository URL: http://hg.python.org/cpython
cpython (merge default -> default): Merge [ In reply to ]
http://hg.python.org/cpython/rev/6762b943ee59
changeset: 76385:6762b943ee59
parent: 76384:c1399cf7bd6a
parent: 76383:22844ddce57b
user: Brett Cannon <brett@python.org>
date: Tue Apr 17 21:42:07 2012 -0400
summary:
Merge

files:
Lib/test/test_keywordonlyarg.py | 6 ++++++
Misc/NEWS | 2 ++
Python/compile.c | 6 +++++-
3 files changed, 13 insertions(+), 1 deletions(-)


diff --git a/Lib/test/test_keywordonlyarg.py b/Lib/test/test_keywordonlyarg.py
--- a/Lib/test/test_keywordonlyarg.py
+++ b/Lib/test/test_keywordonlyarg.py
@@ -170,6 +170,12 @@
# used to fail with a SystemError.
lambda *, k1=unittest: None

+ def test_mangling(self):
+ class X:
+ def f(self, *, __a=42):
+ return __a
+ self.assertEqual(X().f(), 42)
+
def test_main():
run_unittest(KeywordOnlyArgTestCase)

diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -17,6 +17,8 @@
- Issue #14592: Attempting a relative import w/o __package__ or __name__ set in
globals raises a KeyError.

+- Issue #14607: Fix defaults keyword-only arguments which started with ``__``.
+
- Issue #10854: The ImportError raised when an extension module on Windows
fails to import now uses the new path and name attributes from
Issue #1559549.
diff --git a/Python/compile.c b/Python/compile.c
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -1409,7 +1409,11 @@
arg_ty arg = asdl_seq_GET(kwonlyargs, i);
expr_ty default_ = asdl_seq_GET(kw_defaults, i);
if (default_) {
- ADDOP_O(c, LOAD_CONST, arg->arg, consts);
+ PyObject *mangled = _Py_Mangle(c->u->u_private, arg->arg);
+ if (!mangled)
+ return -1;
+ ADDOP_O(c, LOAD_CONST, mangled, consts);
+ Py_DECREF(mangled);
if (!compiler_visit_expr(c, default_)) {
return -1;
}

--
Repository URL: http://hg.python.org/cpython
cpython (merge default -> default): merge [ In reply to ]
http://hg.python.org/cpython/rev/9943bdbbe09c
changeset: 76435:9943bdbbe09c
parent: 76434:573010778eed
parent: 76433:a3d7cfff3688
user: Brett Cannon <brett@python.org>
date: Fri Apr 20 15:23:11 2012 -0400
summary:
merge

files:
Modules/_decimal/libmpdec/mpdecimal.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)


diff --git a/Modules/_decimal/libmpdec/mpdecimal.c b/Modules/_decimal/libmpdec/mpdecimal.c
--- a/Modules/_decimal/libmpdec/mpdecimal.c
+++ b/Modules/_decimal/libmpdec/mpdecimal.c
@@ -3530,6 +3530,7 @@
MPD_NEW_STATIC(r,0,0,0,0);
_mpd_base_ndivmod(q, &r, a, b, status);
if (mpd_isspecial(q) || mpd_isspecial(&r)) {
+ mpd_setspecial(q, MPD_POS, MPD_NAN);
mpd_del(&r);
goto finish;
}

--
Repository URL: http://hg.python.org/cpython
cpython (merge default -> default): Merge [ In reply to ]
http://hg.python.org/cpython/rev/f5a5b2f5c7ef
changeset: 76443:f5a5b2f5c7ef
parent: 76442:b863d7dd113c
parent: 76441:c7b0f711dc15
user: Brett Cannon <brett@python.org>
date: Fri Apr 20 17:19:14 2012 -0400
summary:
Merge

files:
Lib/test/test_long.py | 14 ++++++
Misc/NEWS | 6 ++
Objects/longobject.c | 65 ++++++++++++++++--------------
3 files changed, 54 insertions(+), 31 deletions(-)


diff --git a/Lib/test/test_long.py b/Lib/test/test_long.py
--- a/Lib/test/test_long.py
+++ b/Lib/test/test_long.py
@@ -1228,6 +1228,20 @@
self.assertRaises(TypeError, myint.from_bytes, 0, 'big')
self.assertRaises(TypeError, int.from_bytes, 0, 'big', True)

+ def test_access_to_nonexistent_digit_0(self):
+ # http://bugs.python.org/issue14630: A bug in _PyLong_Copy meant that
+ # ob_digit[0] was being incorrectly accessed for instances of a
+ # subclass of int, with value 0.
+ class Integer(int):
+ def __new__(cls, value=0):
+ self = int.__new__(cls, value)
+ self.foo = 'foo'
+ return self
+
+ integers = [Integer(0) for i in range(1000)]
+ for n in map(int, integers):
+ self.assertEqual(n, 0)
+

def test_main():
support.run_unittest(LongTest)
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -10,6 +10,12 @@
Core and Builtins
-----------------

+- Issue #14630: Fix a memory access bug for instances of a subclass of int
+ with value 0.
+
+- Issue #14339: Speed improvements to bin, oct and hex functions. Patch by
+ Serhiy Storchaka.
+
- Issue #14098: New functions PyErr_GetExcInfo and PyErr_SetExcInfo.
Patch by Stefan Behnel.

diff --git a/Objects/longobject.c b/Objects/longobject.c
--- a/Objects/longobject.c
+++ b/Objects/longobject.c
@@ -156,9 +156,7 @@
if (i < 0)
i = -(i);
if (i < 2) {
- sdigit ival = src->ob_digit[0];
- if (Py_SIZE(src) < 0)
- ival = -ival;
+ sdigit ival = MEDIUM_VALUE(src);
CHECK_SMALL_INT(ival);
}
result = _PyLong_New(i);
@@ -1672,11 +1670,10 @@
{
register PyLongObject *a = (PyLongObject *)aa;
PyObject *v;
- Py_ssize_t i, sz;
+ Py_ssize_t sz;
Py_ssize_t size_a;
- char *p;
- char sign = '\0';
- char *buffer;
+ Py_UCS1 *p;
+ int negative;
int bits;

assert(base == 2 || base == 8 || base == 10 || base == 16);
@@ -1688,6 +1685,7 @@
return NULL;
}
size_a = ABS(Py_SIZE(a));
+ negative = Py_SIZE(a) < 0;

/* Compute a rough upper bound for the length of the string */
switch (base) {
@@ -1704,33 +1702,40 @@
assert(0); /* shouldn't ever get here */
bits = 0; /* to silence gcc warning */
}
- /* compute length of output string: allow 2 characters for prefix and
- 1 for possible '-' sign. */
- if (size_a > (PY_SSIZE_T_MAX - 3) / PyLong_SHIFT / sizeof(Py_UCS4)) {
- PyErr_SetString(PyExc_OverflowError,
- "int is too large to format");
+
+ /* Compute exact length 'sz' of output string. */
+ if (size_a == 0) {
+ sz = 3;
+ }
+ else {
+ Py_ssize_t size_a_in_bits;
+ /* Ensure overflow doesn't occur during computation of sz. */
+ if (size_a > (PY_SSIZE_T_MAX - 3) / PyLong_SHIFT) {
+ PyErr_SetString(PyExc_OverflowError,
+ "int is too large to format");
+ return NULL;
+ }
+ size_a_in_bits = (size_a - 1) * PyLong_SHIFT +
+ bits_in_digit(a->ob_digit[size_a - 1]);
+ /* Allow 2 characters for prefix and 1 for a '-' sign. */
+ sz = 2 + negative + (size_a_in_bits + (bits - 1)) / bits;
+ }
+
+ v = PyUnicode_New(sz, 'x');
+ if (v == NULL) {
return NULL;
}
- /* now size_a * PyLong_SHIFT + 3 <= PY_SSIZE_T_MAX, so the RHS below
- is safe from overflow */
- sz = 3 + (size_a * PyLong_SHIFT + (bits - 1)) / bits;
- assert(sz >= 0);
- buffer = PyMem_Malloc(sz);
- if (buffer == NULL) {
- PyErr_NoMemory();
- return NULL;
- }
- p = &buffer[sz];
- if (Py_SIZE(a) < 0)
- sign = '-';
-
- if (Py_SIZE(a) == 0) {
+ assert(PyUnicode_KIND(v) == PyUnicode_1BYTE_KIND);
+
+ p = PyUnicode_1BYTE_DATA(v) + sz;
+ if (size_a == 0) {
*--p = '0';
}
else {
/* JRH: special case for power-of-2 bases */
twodigits accum = 0;
int accumbits = 0; /* # of bits in accum */
+ Py_ssize_t i;
for (i = 0; i < size_a; ++i) {
accum |= (twodigits)a->ob_digit[i] << accumbits;
accumbits += PyLong_SHIFT;
@@ -1739,7 +1744,6 @@
char cdigit;
cdigit = (char)(accum & (base - 1));
cdigit += (cdigit < 10) ? '0' : 'a'-10;
- assert(p > buffer);
*--p = cdigit;
accumbits -= bits;
accum >>= bits;
@@ -1754,10 +1758,9 @@
else /* (base == 2) */
*--p = 'b';
*--p = '0';
- if (sign)
- *--p = sign;
- v = PyUnicode_DecodeASCII(p, &buffer[sz] - p, NULL);
- PyMem_Free(buffer);
+ if (negative)
+ *--p = '-';
+ assert(p == PyUnicode_1BYTE_DATA(v));
return v;
}


--
Repository URL: http://hg.python.org/cpython
cpython (merge default -> default): merge [ In reply to ]
http://hg.python.org/cpython/rev/1296da8b216f
changeset: 76452:1296da8b216f
parent: 76451:ea46ebba8a0f
parent: 76448:d7c8914a9c4d
user: Brett Cannon <brett@python.org>
date: Sat Apr 21 18:53:14 2012 -0400
summary:
merge

files:
Doc/library/inspect.rst | 13 ++-
Doc/library/unittest.mock-examples.rst | 49 -----------
Doc/library/unittest.mock.rst | 14 +++
Lib/unittest/mock.py | 20 +++-
Lib/unittest/test/testmock/testhelpers.py | 15 +++-
Lib/unittest/test/testmock/testmock.py | 10 ++
6 files changed, 61 insertions(+), 60 deletions(-)


diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst
--- a/Doc/library/inspect.rst
+++ b/Doc/library/inspect.rst
@@ -440,11 +440,16 @@
locals dictionary of the given frame.


-.. function:: formatargspec(args[, varargs, varkw, defaults, formatarg, formatvarargs, formatvarkw, formatvalue])
+.. function:: formatargspec(args[., varargs, varkw, defaults, kwonlyargs, kwonlydefaults, annotations, formatarg, formatvarargs, formatvarkw, formatvalue, formatreturns, formatannotations])

- Format a pretty argument spec from the four values returned by
- :func:`getargspec`. The format\* arguments are the corresponding optional
- formatting functions that are called to turn names and values into strings.
+ Format a pretty argument spec from the values returned by
+ :func:`getargspec` or :func:`getfullargspec`.
+
+ The first seven arguments are (``args``, ``varargs``, ``varkw``,
+ ``defaults``, ``kwonlyargs``, ``kwonlydefaults``, ``annotations``). The
+ other five arguments are the corresponding optional formatting functions
+ that are called to turn names and values into strings. The last argument
+ is an optional function to format the sequence of arguments.


.. function:: formatargvalues(args[, varargs, varkw, locals, formatarg, formatvarargs, formatvarkw, formatvalue])
diff --git a/Doc/library/unittest.mock-examples.rst b/Doc/library/unittest.mock-examples.rst
--- a/Doc/library/unittest.mock-examples.rst
+++ b/Doc/library/unittest.mock-examples.rst
@@ -838,56 +838,6 @@
children of a `CopyingMock` will also have the type `CopyingMock`.


-Multiple calls with different effects
--------------------------------------
-
-Handling code that needs to behave differently on subsequent calls during the
-test can be tricky. For example you may have a function that needs to raise
-an exception the first time it is called but returns a response on the second
-call (testing retry behaviour).
-
-One approach is to use a :attr:`side_effect` function that replaces itself. The
-first time it is called the `side_effect` sets a new `side_effect` that will
-be used for the second call. It then raises an exception:
-
- >>> def side_effect(*args):
- ... def second_call(*args):
- ... return 'response'
- ... mock.side_effect = second_call
- ... raise Exception('boom')
- ...
- >>> mock = Mock(side_effect=side_effect)
- >>> mock('first')
- Traceback (most recent call last):
- ...
- Exception: boom
- >>> mock('second')
- 'response'
- >>> mock.assert_called_with('second')
-
-Another perfectly valid way would be to pop return values from a list. If the
-return value is an exception, raise it instead of returning it:
-
- >>> returns = [Exception('boom'), 'response']
- >>> def side_effect(*args):
- ... result = returns.pop(0)
- ... if isinstance(result, Exception):
- ... raise result
- ... return result
- ...
- >>> mock = Mock(side_effect=side_effect)
- >>> mock('first')
- Traceback (most recent call last):
- ...
- Exception: boom
- >>> mock('second')
- 'response'
- >>> mock.assert_called_with('second')
-
-Which approach you prefer is a matter of taste. The first approach is actually
-a line shorter but maybe the second approach is more readable.
-
-
Nesting Patches
---------------

diff --git a/Doc/library/unittest.mock.rst b/Doc/library/unittest.mock.rst
--- a/Doc/library/unittest.mock.rst
+++ b/Doc/library/unittest.mock.rst
@@ -823,6 +823,20 @@
...
StopIteration

+If any members of the iterable are exceptions they will be raised instead of
+returned::
+
+ >>> iterable = (33, ValueError, 66)
+ >>> m = MagicMock(side_effect=iterable)
+ >>> m()
+ 33
+ >>> m()
+ Traceback (most recent call last):
+ ...
+ ValueError
+ >>> m()
+ 66
+

.. _deleting-attributes:

diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py
--- a/Lib/unittest/mock.py
+++ b/Lib/unittest/mock.py
@@ -78,11 +78,14 @@
return

try:
- regargs, varargs, varkwargs, defaults = inspect.getargspec(func)
+ argspec = inspect.getfullargspec(func)
except TypeError:
# C function / method, possibly inherited object().__init__
return

+ regargs, varargs, varkw, defaults, kwonly, kwonlydef, ann = argspec
+
+
# instance methods and classmethods need to lose the self argument
if getattr(func, '__self__', None) is not None:
regargs = regargs[1:]
@@ -90,8 +93,9 @@
# this condition and the above one are never both True - why?
regargs = regargs[1:]

- signature = inspect.formatargspec(regargs, varargs, varkwargs, defaults,
- formatvalue=lambda value: "")
+ signature = inspect.formatargspec(
+ regargs, varargs, varkw, defaults,
+ kwonly, kwonlydef, ann, formatvalue=lambda value: "")
return signature[1:-1], func


@@ -891,7 +895,10 @@
raise effect

if not _callable(effect):
- return next(effect)
+ result = next(effect)
+ if _is_exception(result):
+ raise result
+ return result

ret_val = effect(*args, **kwargs)
if ret_val is DEFAULT:
@@ -931,8 +938,9 @@
arguments as the mock, and unless it returns `DEFAULT`, the return
value of this function is used as the return value.

- Alternatively `side_effect` can be an exception class or instance. In
- this case the exception will be raised when the mock is called.
+ If `side_effect` is an iterable then each call to the mock will return
+ the next value from the iterable. If any of the members of the iterable
+ are exceptions they will be raised instead of returned.

If `side_effect` is an iterable then each call to the mock will return
the next value from the iterable.
diff --git a/Lib/unittest/test/testmock/testhelpers.py b/Lib/unittest/test/testmock/testhelpers.py
--- a/Lib/unittest/test/testmock/testhelpers.py
+++ b/Lib/unittest/test/testmock/testhelpers.py
@@ -367,7 +367,7 @@


def test_create_autospec_unbound_methods(self):
- # see issue 128
+ # see mock issue 128
# this is expected to fail until the issue is fixed
return
class Foo(object):
@@ -391,6 +391,19 @@
self.assertEqual(m.a, '3')


+ def test_create_autospec_keyword_only_arguments(self):
+ def foo(a, *, b=None):
+ pass
+
+ m = create_autospec(foo)
+ m(1)
+ m.assert_called_with(1)
+ self.assertRaises(TypeError, m, 1, 2)
+
+ m(2, b=3)
+ m.assert_called_with(2, b=3)
+
+
def test_function_as_instance_attribute(self):
obj = SomeClass()
def f(a):
diff --git a/Lib/unittest/test/testmock/testmock.py b/Lib/unittest/test/testmock/testmock.py
--- a/Lib/unittest/test/testmock/testmock.py
+++ b/Lib/unittest/test/testmock/testmock.py
@@ -868,6 +868,16 @@
self.assertRaises(StopIteration, mock)


+ def test_side_effect_iterator_exceptions(self):
+ for Klass in Mock, MagicMock:
+ iterable = (ValueError, 3, KeyError, 6)
+ m = Klass(side_effect=iterable)
+ self.assertRaises(ValueError, m)
+ self.assertEqual(m(), 3)
+ self.assertRaises(KeyError, m)
+ self.assertEqual(m(), 6)
+
+
def test_side_effect_setting_iterator(self):
mock = Mock()
mock.side_effect = iter([1, 2, 3])

--
Repository URL: http://hg.python.org/cpython
cpython (merge default -> default): merge [ In reply to ]
http://hg.python.org/cpython/rev/79f55cf917fd
changeset: 76460:79f55cf917fd
parent: 76459:b8cd8dd7006a
parent: 76458:943e0520476f
user: Brett Cannon <brett@python.org>
date: Sat Apr 21 21:21:54 2012 -0400
summary:
merge

files:
Lib/http/cookies.py | 2 +-
Lib/test/test_http_cookies.py | 9 +++++++++
Misc/NEWS | 2 ++
3 files changed, 12 insertions(+), 1 deletions(-)


diff --git a/Lib/http/cookies.py b/Lib/http/cookies.py
--- a/Lib/http/cookies.py
+++ b/Lib/http/cookies.py
@@ -159,7 +159,7 @@
# _LegalChars is the list of chars which don't require "'s
# _Translator hash-table for fast quoting
#
-_LegalChars = string.ascii_letters + string.digits + "!#$%&'*+-.^_`|~"
+_LegalChars = string.ascii_letters + string.digits + "!#$%&'*+-.^_`|~:"
_Translator = {
'\000' : '\\000', '\001' : '\\001', '\002' : '\\002',
'\003' : '\\003', '\004' : '\\004', '\005' : '\\005',
diff --git a/Lib/test/test_http_cookies.py b/Lib/test/test_http_cookies.py
--- a/Lib/test/test_http_cookies.py
+++ b/Lib/test/test_http_cookies.py
@@ -34,6 +34,15 @@
'dict': {'keebler' : 'E=mc2'},
'repr': "<SimpleCookie: keebler='E=mc2'>",
'output': 'Set-Cookie: keebler=E=mc2'},
+
+ # Cookies with ':' character in their name. Though not mentioned in
+ # RFC, servers / browsers allow it.
+
+ {'data': 'key:term=value:term',
+ 'dict': {'key:term' : 'value:term'},
+ 'repr': "<SimpleCookie: key:term='value:term'>",
+ 'output': 'Set-Cookie: key:term=value:term'},
+
]

for case in cases:
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -61,6 +61,8 @@
Library
-------

+- Issue #2193: Allow ":" character in Cookie NAME values.
+
- Issue #14629: tokenizer.detect_encoding will specify the filename in the
SyntaxError exception if found at readline.__self__.name.


--
Repository URL: http://hg.python.org/cpython
cpython (merge default -> default): merge [ In reply to ]
http://hg.python.org/cpython/rev/765ca3caee10
changeset: 76467:765ca3caee10
parent: 76466:9adfe3c0fe48
parent: 76465:8cae3ee7f691
user: Brett Cannon <brett@python.org>
date: Sun Apr 22 02:06:48 2012 -0400
summary:
merge

files:
Doc/library/http.cookies.rst | 13 +++++++++++--
1 files changed, 11 insertions(+), 2 deletions(-)


diff --git a/Doc/library/http.cookies.rst b/Doc/library/http.cookies.rst
--- a/Doc/library/http.cookies.rst
+++ b/Doc/library/http.cookies.rst
@@ -17,8 +17,17 @@

The module formerly strictly applied the parsing rules described in the
:rfc:`2109` and :rfc:`2068` specifications. It has since been discovered that
-MSIE 3.0x doesn't follow the character rules outlined in those specs. As a
-result, the parsing rules used are a bit less strict.
+MSIE 3.0x doesn't follow the character rules outlined in those specs and also
+many current day browsers and servers have relaxed parsing rules when comes to
+Cookie handling. As a result, the parsing rules used are a bit less strict.
+
+The character set, :data:`string.ascii_letters`, :data:`string.digits` and
+``!#$%&'*+-.^_`|~:`` denote the set of valid characters allowed by this module
+in Cookie name (as :attr:`~Morsel.key`).
+
+.. versionchanged:: 3.3
+ Allowed ':' as a valid Cookie name character.
+

.. note::


--
Repository URL: http://hg.python.org/cpython
cpython (merge default -> default): merge [ In reply to ]
http://hg.python.org/cpython/rev/9afdbef0622f
changeset: 76473:9afdbef0622f
parent: 76472:4e853913054c
parent: 76471:b3a565e9701e
user: Brett Cannon <brett@python.org>
date: Sun Apr 22 13:02:31 2012 -0400
summary:
merge

files:
Lib/os.py | 11 ++---------
Lib/test/test_cmd_line_script.py | 11 ++++++++---
Misc/NEWS | 3 +++
3 files changed, 13 insertions(+), 12 deletions(-)


diff --git a/Lib/os.py b/Lib/os.py
--- a/Lib/os.py
+++ b/Lib/os.py
@@ -126,13 +126,6 @@
umask(mask)
return mode & ~mask

-def _are_same_file(stat1, stat2):
- """Helper function that checks whether two stat results refer to the same
- file.
- """
- return (stat1.st_ino == stat2.st_ino and stat1.st_dev == stat2.st_dev)
-#
-
# Super directory utilities.
# (Inspired by Eric Raymond; the doc strings are mostly his)

@@ -345,7 +338,7 @@
topfd = open(top, O_RDONLY)
try:
if (followlinks or (st.S_ISDIR(orig_st.st_mode) and
- _are_same_file(orig_st, fstat(topfd)))):
+ path.samestat(orig_st, fstat(topfd)))):
for x in _fwalk(topfd, top, topdown, onerror, followlinks):
yield x
finally:
@@ -382,7 +375,7 @@
onerror(err)
return
try:
- if followlinks or _are_same_file(orig_st, fstat(dirfd)):
+ if followlinks or path.samestat(orig_st, fstat(dirfd)):
dirpath = path.join(toppath, name)
for x in _fwalk(dirfd, dirpath, topdown, onerror, followlinks):
yield x
diff --git a/Lib/test/test_cmd_line_script.py b/Lib/test/test_cmd_line_script.py
--- a/Lib/test/test_cmd_line_script.py
+++ b/Lib/test/test_cmd_line_script.py
@@ -13,6 +13,8 @@

verbose = support.verbose

+example_args = ['test1', 'test2', 'test3']
+
test_source = """\
# Script may be run with optimisation enabled, so don't rely on assert
# statements being executed
@@ -36,6 +38,9 @@
# Check the sys module
import sys
assertIdentical(globals(), sys.modules[__name__].__dict__)
+from test import test_cmd_line_script
+example_args_list = test_cmd_line_script.example_args
+assertEqual(sys.argv[1:], example_args_list)
print('sys.argv[0]==%a' % sys.argv[0])
print('sys.path[0]==%a' % sys.path[0])
# Check the working directory
@@ -100,7 +105,7 @@
*cmd_line_switches):
if not __debug__:
cmd_line_switches += ('-' + 'O' * sys.flags.optimize,)
- run_args = cmd_line_switches + (script_name,)
+ run_args = cmd_line_switches + (script_name,) + tuple(example_args)
rc, out, err = assert_python_ok(*run_args)
self._check_output(script_name, rc, out + err, expected_file,
expected_argv0, expected_path0, expected_package)
@@ -240,7 +245,7 @@
pkg_dir = os.path.join(script_dir, 'test_pkg')
make_pkg(pkg_dir, "import sys; print('init_argv0==%r' % sys.argv[0])")
script_name = _make_test_script(pkg_dir, 'script')
- rc, out, err = assert_python_ok('-m', 'test_pkg.script')
+ rc, out, err = assert_python_ok('-m', 'test_pkg.script', *example_args)
if verbose > 1:
print(out)
expected = "init_argv0==%r" % '-m'
@@ -270,7 +275,7 @@
with support.temp_cwd(path=script_dir):
with open("-m", "w") as f:
f.write("data")
- rc, out, err = assert_python_ok('-m', 'other')
+ rc, out, err = assert_python_ok('-m', 'other', *example_args)
self._check_output(script_name, rc, out,
script_name, script_name, '', '')

diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -146,6 +146,9 @@
Tests
-----

+- Issue #14026: In test_cmd_line_script, check that sys.argv is populated
+ correctly for the various invocation approaches (Patch by Jason Yeo)
+
- Issue #14032: Fix incorrect variable name in test_cmd_line_script debugging
message (Patch by Jason Yeo)


--
Repository URL: http://hg.python.org/cpython
cpython (merge default -> default): merge [ In reply to ]
http://hg.python.org/cpython/rev/0a79a2add552
changeset: 76477:0a79a2add552
parent: 76476:2a7f445f71eb
parent: 76475:bdbcb8f48ddd
user: Brett Cannon <brett@python.org>
date: Sun Apr 22 13:30:07 2012 -0400
summary:
merge

files:
Lib/logging/handlers.py | 2 +-
Lib/test/test_logging.py | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)


diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py
--- a/Lib/logging/handlers.py
+++ b/Lib/logging/handlers.py
@@ -872,7 +872,7 @@
A handler class which sends an SMTP email for each logging event.
"""
def __init__(self, mailhost, fromaddr, toaddrs, subject,
- credentials=None, secure=None, timeout=1.0):
+ credentials=None, secure=None, timeout=5.0):
"""
Initialize the handler.

diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py
--- a/Lib/test/test_logging.py
+++ b/Lib/test/test_logging.py
@@ -930,7 +930,7 @@
sockmap)
server.start()
addr = ('localhost', server.port)
- h = logging.handlers.SMTPHandler(addr, 'me', 'you', 'Log')
+ h = logging.handlers.SMTPHandler(addr, 'me', 'you', 'Log', timeout=5.0)
self.assertEqual(h.toaddrs, ['you'])
self.messages = []
r = logging.makeLogRecord({'msg': 'Hello'})

--
Repository URL: http://hg.python.org/cpython
cpython (merge default -> default): Merge [ In reply to ]
http://hg.python.org/cpython/rev/37b03d64883a
changeset: 76563:37b03d64883a
parent: 76562:8dab93ec19de
parent: 76561:004f8d96f573
user: Brett Cannon <brett@python.org>
date: Wed Apr 25 20:18:24 2012 -0400
summary:
Merge

files:
Lib/importlib/_bootstrap.py | 7 ++
Lib/test/test_logging.py | 36 +++++++-------
Lib/unittest/case.py | 2 +-
Lib/unittest/test/test_skipping.py | 15 ++++++
Makefile.pre.in | 15 +++++-
Misc/NEWS | 6 ++
Objects/longobject.c | 2 +
Objects/unicodeobject.c | 8 ++-
Python/importlib.h | Bin
Tools/msi/msi.py | 22 +++++++-
Tools/scripts/import_diagnostics.py | 39 ++++++++++++++++
11 files changed, 126 insertions(+), 26 deletions(-)


diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py
--- a/Lib/importlib/_bootstrap.py
+++ b/Lib/importlib/_bootstrap.py
@@ -6,6 +6,13 @@
work. One should use importlib as the public-facing version of this module.

"""
+#
+# IMPORTANT: Whenever making changes to this module, be sure to run
+# a top-level make in order to get the frozen version of the module
+# update. Not doing so, will result in the Makefile to fail for
+# all others who don't have a ./python around to freeze the module
+# in the early stages of compilation.
+#

# See importlib._setup() for what is injected into the global namespace.

diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py
--- a/Lib/test/test_logging.py
+++ b/Lib/test/test_logging.py
@@ -593,28 +593,28 @@
pass
time.sleep(0.004 * random.randint(0, 4))

- def cleanup(remover, fn, handler):
- handler.close()
- remover.join()
- if os.path.exists(fn):
- os.unlink(fn)
-
- fd, fn = tempfile.mkstemp('.log', 'test_logging-3-')
- os.close(fd)
- del_count = 1000
- log_count = 1000
- remover = threading.Thread(target=remove_loop, args=(fn, del_count))
- remover.daemon = True
- remover.start()
+ del_count = 500
+ log_count = 500
+
for delay in (False, True):
+ fd, fn = tempfile.mkstemp('.log', 'test_logging-3-')
+ os.close(fd)
+ remover = threading.Thread(target=remove_loop, args=(fn, del_count))
+ remover.daemon = True
+ remover.start()
h = logging.handlers.WatchedFileHandler(fn, delay=delay)
- self.addCleanup(cleanup, remover, fn, h)
f = logging.Formatter('%(asctime)s: %(levelname)s: %(message)s')
h.setFormatter(f)
- for _ in range(log_count):
- time.sleep(0.005)
- r = logging.makeLogRecord({'msg': 'testing' })
- h.handle(r)
+ try:
+ for _ in range(log_count):
+ time.sleep(0.005)
+ r = logging.makeLogRecord({'msg': 'testing' })
+ h.handle(r)
+ finally:
+ h.close()
+ remover.join()
+ if os.path.exists(fn):
+ os.unlink(fn)


class BadStream(object):
diff --git a/Lib/unittest/case.py b/Lib/unittest/case.py
--- a/Lib/unittest/case.py
+++ b/Lib/unittest/case.py
@@ -61,7 +61,7 @@
Unconditionally skip a test.
"""
def decorator(test_item):
- if not (isinstance(test_item, type) and issubclass(test_item, TestCase)):
+ if not isinstance(test_item, type):
@functools.wraps(test_item)
def skip_wrapper(*args, **kwargs):
raise SkipTest(reason)
diff --git a/Lib/unittest/test/test_skipping.py b/Lib/unittest/test/test_skipping.py
--- a/Lib/unittest/test/test_skipping.py
+++ b/Lib/unittest/test/test_skipping.py
@@ -66,6 +66,21 @@
self.assertEqual(result.skipped, [(test, "testing")])
self.assertEqual(record, [])

+ def test_skip_non_unittest_class(self):
+ @unittest.skip("testing")
+ class Mixin:
+ def test_1(self):
+ record.append(1)
+ class Foo(Mixin, unittest.TestCase):
+ pass
+ record = []
+ result = unittest.TestResult()
+ test = Foo("test_1")
+ suite = unittest.TestSuite([test])
+ suite.run(result)
+ self.assertEqual(result.skipped, [(test, "testing")])
+ self.assertEqual(record, [])
+
def test_expected_failure(self):
class Foo(unittest.TestCase):
@unittest.expectedFailure
diff --git a/Makefile.pre.in b/Makefile.pre.in
--- a/Makefile.pre.in
+++ b/Makefile.pre.in
@@ -573,12 +573,23 @@

Modules/_testembed: Modules/_testembed.o $(LIBRARY) $(LDLIBRARY) $(PY3LIBRARY)
$(LINKCC) $(PY_LDFLAGS) $(LINKFORSHARED) -o $@ Modules/_testembed.o $(BLDLIBRARY) $(LIBS) $(MODLIBS) $(SYSLIBS) $(LDLAST)
+
############################################################################
# Importlib

Python/importlib.h: $(srcdir)/Lib/importlib/_bootstrap.py $(srcdir)/Python/freeze_importlib.py
- ./$(BUILDPYTHON) $(srcdir)/Python/freeze_importlib.py \
- $(srcdir)/Lib/importlib/_bootstrap.py Python/importlib.h
+ @if test -f ./$(BUILDPYTHON); then \
+ ./$(BUILDPYTHON) $(srcdir)/Python/freeze_importlib.py \
+ $(srcdir)/Lib/importlib/_bootstrap.py Python/importlib.h; \
+ else \
+ echo "----------------------------------------------------------"; \
+ echo "Python/importlib.h needs to be rebuilt, but no interpreter"; \
+ echo "is available to do so. Leaving the previous version in"; \
+ echo "place. You may want to run ''make'' a second time after"; \
+ echo "this build is complete."; \
+ echo "----------------------------------------------------------"; \
+ fi
+
############################################################################
# Special rules for object files

diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -71,6 +71,9 @@
Library
-------

+- Issue #14664: It is now possible to use @unittest.skip{If,Unless} on a
+ test class that doesn't inherit from TestCase (i.e. a mixin).
+
- Issue #4892: multiprocessing Connections can now be transferred over
multiprocessing Connections. Patch by Richard Oudkerk (sbt).

@@ -186,6 +189,9 @@
Tools / Demos
-------------

+- Issue #3561: The Windows installer now has an option, off by default, for
+ placing the Python installation into the system "Path" environment variable.
+
- Issue #13165: stringbench is now available in the Tools/stringbench folder.
It used to live in its own SVN project.

diff --git a/Objects/longobject.c b/Objects/longobject.c
--- a/Objects/longobject.c
+++ b/Objects/longobject.c
@@ -1657,6 +1657,7 @@

/* check we've counted correctly */
assert(p == PyUnicode_1BYTE_DATA(str));
+ assert(_PyUnicode_CheckConsistency(str, 1));
Py_DECREF(scratch);
return (PyObject *)str;
}
@@ -1761,6 +1762,7 @@
if (negative)
*--p = '-';
assert(p == PyUnicode_1BYTE_DATA(v));
+ assert(_PyUnicode_CheckConsistency(v, 1));
return v;
}

diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c
--- a/Objects/unicodeobject.c
+++ b/Objects/unicodeobject.c
@@ -375,10 +375,13 @@
{
Py_ssize_t i;
Py_UCS4 maxchar = 0;
- void *data = PyUnicode_DATA(ascii);
+ void *data;
+ Py_UCS4 ch;
+
+ data = PyUnicode_DATA(ascii);
for (i=0; i < ascii->length; i++)
{
- Py_UCS4 ch = PyUnicode_READ(kind, data, i);
+ ch = PyUnicode_READ(kind, data, i);
if (ch > maxchar)
maxchar = ch;
}
@@ -398,6 +401,7 @@
assert(maxchar >= 0x10000);
assert(maxchar <= MAX_UNICODE);
}
+ assert(PyUnicode_READ(kind, data, ascii->length) == 0);
}
return 1;
}
diff --git a/Python/importlib.h b/Python/importlib.h
index 8bc0d8128cdbb869055d5c9ddfb53b6cbc17e32d..9dbd8816f3060d4ea66d3db7b1980139214e3908
GIT binary patch
[stripped]
diff --git a/Tools/msi/msi.py b/Tools/msi/msi.py
--- a/Tools/msi/msi.py
+++ b/Tools/msi/msi.py
@@ -454,6 +454,10 @@
("SetDLLDirToTarget", 'DLLDIR=""', 751),
])

+ # Prepend TARGETDIR to the system path, and remove it on uninstall.
+ add_data(db, "Environment",
+ [("PathAddition", "=-*Path", "[TARGETDIR];[~]", "REGISTRY.path")])
+
# Execute Sequences
add_data(db, "InstallExecuteSequence",
[.("InitialTargetDir", 'TARGETDIR=""', 750),
@@ -677,11 +681,11 @@
c=features.xbutton("Advanced", "Advanced", None, 0.30)
c.event("SpawnDialog", "AdvancedDlg")

- c=features.text("ItemDescription", 140, 180, 210, 30, 3,
+ c=features.text("ItemDescription", 140, 180, 210, 40, 3,
"Multiline description of the currently selected item.")
c.mapping("SelectionDescription","Text")

- c=features.text("ItemSize", 140, 210, 210, 45, 3,
+ c=features.text("ItemSize", 140, 225, 210, 33, 3,
"The size of the currently selected item.")
c.mapping("SelectionSize", "Text")

@@ -835,7 +839,7 @@
# (i.e. additional Python libraries) need to follow the parent feature.
# Features that have no advertisement trigger (e.g. the test suite)
# must not support advertisement
- global default_feature, tcltk, htmlfiles, tools, testsuite, ext_feature, private_crt
+ global default_feature, tcltk, htmlfiles, tools, testsuite, ext_feature, private_crt, prepend_path
default_feature = Feature(db, "DefaultFeature", "Python",
"Python Interpreter and Libraries",
1, directory = "TARGETDIR")
@@ -860,6 +864,15 @@
testsuite = Feature(db, "Testsuite", "Test suite",
"Python test suite (Lib/test/)", 11,
parent = default_feature, attributes=2|8)
+ # prepend_path is an additional feature which is to be off by default.
+ # Since the default level for the above features is 1, this needs to be
+ # at least level higher.
+ prepend_path = Feature(db, "PrependPath", "Add python.exe to Path",
+ "Prepend [TARGETDIR] to the system Path variable. "
+ "This allows you to type 'python' into a command "
+ "prompt without needing the full path.", 13,
+ parent = default_feature, attributes=2|8,
+ level=2)

def extract_msvcr90():
# Find the redistributable files
@@ -1146,6 +1159,8 @@
"InstallPath"),
("REGISTRY.doc", msilib.gen_uuid(), "TARGETDIR", registry_component, None,
"Documentation"),
+ ("REGISTRY.path", msilib.gen_uuid(), "TARGETDIR", registry_component, None,
+ None),
("REGISTRY.def", msilib.gen_uuid(), "TARGETDIR", registry_component,
None, None)] + tcldata)
# See "FeatureComponents Table".
@@ -1162,6 +1177,7 @@
add_data(db, "FeatureComponents",
[(default_feature.id, "REGISTRY"),
(htmlfiles.id, "REGISTRY.doc"),
+ (prepend_path.id, "REGISTRY.path"),
(ext_feature.id, "REGISTRY.def")] +
tcldata
)
diff --git a/Tools/scripts/import_diagnostics.py b/Tools/scripts/import_diagnostics.py
new file mode 100755
--- /dev/null
+++ b/Tools/scripts/import_diagnostics.py
@@ -0,0 +1,39 @@
+#!/usr/bin/env python3
+"""Miscellaneous diagnostics for the import system"""
+
+import sys
+import argparse
+from pprint import pprint
+
+def _dump_state(args):
+ print(sys.version)
+ print("sys.path:")
+ pprint(sys.path)
+ print("sys.meta_path")
+ pprint(sys.meta_path)
+ print("sys.path_hooks")
+ pprint(sys.path_hooks)
+ print("sys.path_importer_cache")
+ pprint(sys.path_importer_cache)
+ print("sys.modules:")
+ pprint(sys.modules)
+
+COMMANDS = (
+ ("dump", "Dump import state", _dump_state),
+)
+
+def _make_parser():
+ parser = argparse.ArgumentParser()
+ sub = parser.add_subparsers(title="Commands")
+ for name, description, implementation in COMMANDS:
+ cmd = sub.add_parser(name, help=description)
+ cmd.set_defaults(command=implementation)
+ return parser
+
+def main(args):
+ parser = _make_parser()
+ args = parser.parse_args(args)
+ return args.command(args)
+
+if __name__ == "__main__":
+ sys.exit(main(sys.argv[1:]))

--
Repository URL: http://hg.python.org/cpython
cpython (merge default -> default): merge [ In reply to ]
http://hg.python.org/cpython/rev/f90c735e7699
changeset: 76580:f90c735e7699
parent: 76579:3bd60cc27664
parent: 76575:1c8a79c4c73e
user: Brett Cannon <brett@python.org>
date: Fri Apr 27 14:02:33 2012 -0400
summary:
merge

files:
Tools/hg/hgtouch.py | 12 ++++++++----
1 files changed, 8 insertions(+), 4 deletions(-)


diff --git a/Tools/hg/hgtouch.py b/Tools/hg/hgtouch.py
--- a/Tools/hg/hgtouch.py
+++ b/Tools/hg/hgtouch.py
@@ -7,15 +7,19 @@

In addition to the dependency syntax, #-comments are supported.
"""
+import errno
import os

def parse_config(repo):
- configfile = repo.wjoin(".hgtouch")
- if not os.path.exists(configfile):
+ try:
+ fp = repo.wfile(".hgtouch")
+ except IOError, e:
+ if e.errno != errno.ENOENT:
+ raise
return {}
result = {}
- with open(configfile) as f:
- for line in f:
+ with fp:
+ for line in fp:
# strip comments
line = line.split('#')[0].strip()
if ':' not in line:

--
Repository URL: http://hg.python.org/cpython
cpython (merge default -> default): merge [ In reply to ]
http://hg.python.org/cpython/rev/cbaaf95476e7
changeset: 76583:cbaaf95476e7
parent: 76582:7025ee00dbf6
parent: 76581:a3beae842f13
user: Brett Cannon <brett@python.org>
date: Fri Apr 27 15:31:45 2012 -0400
summary:
merge

files:
Objects/typeobject.c | 8 +++++---
1 files changed, 5 insertions(+), 3 deletions(-)


diff --git a/Objects/typeobject.c b/Objects/typeobject.c
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -2593,6 +2593,9 @@
return update_slot(type, name);
}

+extern void
+_PyDictKeys_DecRef(PyDictKeysObject *keys);
+
static void
type_dealloc(PyTypeObject *type)
{
@@ -2616,6 +2619,8 @@
Py_XDECREF(et->ht_name);
Py_XDECREF(et->ht_qualname);
Py_XDECREF(et->ht_slots);
+ if (et->ht_cached_keys)
+ _PyDictKeys_DecRef(et->ht_cached_keys);
Py_TYPE(type)->tp_free((PyObject *)type);
}

@@ -2791,9 +2796,6 @@
return 0;
}

-extern void
-_PyDictKeys_DecRef(PyDictKeysObject *keys);
-
static int
type_clear(PyTypeObject *type)
{

--
Repository URL: http://hg.python.org/cpython
cpython (merge default -> default): merge [ In reply to ]
http://hg.python.org/cpython/rev/69ea85992b3d
changeset: 76587:69ea85992b3d
parent: 76586:496c68f90a03
parent: 76585:d27440b2f318
user: Brett Cannon <brett@python.org>
date: Fri Apr 27 17:27:33 2012 -0400
summary:
merge

files:
Objects/unicodeobject.c | 3 +++
1 files changed, 3 insertions(+), 0 deletions(-)


diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c
--- a/Objects/unicodeobject.c
+++ b/Objects/unicodeobject.c
@@ -1985,6 +1985,9 @@
if (start == end)
return 127;

+ if (PyUnicode_IS_ASCII(unicode))
+ return 127;
+
kind = PyUnicode_KIND(unicode);
startptr = PyUnicode_DATA(unicode);
endptr = (char *)startptr + end * kind;

--
Repository URL: http://hg.python.org/cpython
cpython (merge default -> default): merge [ In reply to ]
http://hg.python.org/cpython/rev/534cbebd7a71
changeset: 76634:534cbebd7a71
parent: 76633:eb5c5c23ca9b
parent: 76632:16635c81b329
user: Brett Cannon <brett@python.org>
date: Sun Apr 29 12:50:32 2012 -0400
summary:
merge

files:
Doc/howto/sorting.rst | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)


diff --git a/Doc/howto/sorting.rst b/Doc/howto/sorting.rst
--- a/Doc/howto/sorting.rst
+++ b/Doc/howto/sorting.rst
@@ -42,7 +42,7 @@
Key Functions
=============

-Both :meth:`list.sort` and :func:`sorted` have *key* parameter to specify a
+Both :meth:`list.sort` and :func:`sorted` have a *key* parameter to specify a
function to be called on each list element prior to making comparisons.

For example, here's a case-insensitive string comparison:
@@ -89,7 +89,7 @@
The key-function patterns shown above are very common, so Python provides
convenience functions to make accessor functions easier and faster. The
:mod:`operator` module has :func:`~operator.itemgetter`,
-:func:`~operator.attrgetter`, and an :func:`~operator.methodcaller` function.
+:func:`~operator.attrgetter`, and a :func:`~operator.methodcaller` function.

Using those functions, the above examples become simpler and faster:

@@ -114,7 +114,7 @@
========================

Both :meth:`list.sort` and :func:`sorted` accept a *reverse* parameter with a
-boolean value. This is using to flag descending sorts. For example, to get the
+boolean value. This is used to flag descending sorts. For example, to get the
student data in reverse *age* order:

>>> sorted(student_tuples, key=itemgetter(2), reverse=True)

--
Repository URL: http://hg.python.org/cpython
cpython (merge default -> default): merge [ In reply to ]
http://hg.python.org/cpython/rev/40a05f9eb4c6
changeset: 76641:40a05f9eb4c6
parent: 76640:eb68502731dd
parent: 76639:925fbcfbbc45
user: Brett Cannon <brett@python.org>
date: Sun Apr 29 14:38:57 2012 -0400
summary:
merge

files:
Doc/library/stdtypes.rst | 2 +-
Lib/test/test_float.py | 10 ----------
2 files changed, 1 insertions(+), 11 deletions(-)


diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst
--- a/Doc/library/stdtypes.rst
+++ b/Doc/library/stdtypes.rst
@@ -2459,7 +2459,7 @@
bytearray(b'z123fg')
>>> v[2:3] = b'spam'
Traceback (most recent call last):
- File "<stdin>", line 1, in <module>
+ File "<stdin>", line 1, in <module>
ValueError: memoryview assignment: lvalue and rvalue have different structures
>>> v[2:6] = b'spam'
>>> data
diff --git a/Lib/test/test_float.py b/Lib/test/test_float.py
--- a/Lib/test/test_float.py
+++ b/Lib/test/test_float.py
@@ -860,16 +860,6 @@
self.assertEqual(str(1e300 * 1e300 * 0), "nan")
self.assertEqual(str(-1e300 * 1e300 * 0), "nan")

- def notest_float_nan(self):
- self.assertTrue(NAN.is_nan())
- self.assertFalse(INF.is_nan())
- self.assertFalse((0.).is_nan())
-
- def notest_float_inf(self):
- self.assertTrue(INF.is_inf())
- self.assertFalse(NAN.is_inf())
- self.assertFalse((0.).is_inf())
-
def test_inf_signs(self):
self.assertEqual(copysign(1.0, float('inf')), 1.0)
self.assertEqual(copysign(1.0, float('-inf')), -1.0)

--
Repository URL: http://hg.python.org/cpython
cpython (merge default -> default): merge [ In reply to ]
http://hg.python.org/cpython/rev/e14ed98fc33c
changeset: 76646:e14ed98fc33c
parent: 76643:399cb1afb747
parent: 76645:6e029b6c142a
user: Alexander Belopolsky <alexander.belopolsky@gmail.com>
date: Sun Apr 29 16:34:43 2012 -0400
summary:
merge

files:
Lib/imaplib.py | 16 ++-----------
Lib/test/support.py | 31 +++++++++++++++++++++++++++-
Lib/test/test_imaplib.py | 9 +++++++-
Misc/ACKS | 1 +
Misc/NEWS | 3 ++
5 files changed, 45 insertions(+), 15 deletions(-)


diff --git a/Lib/imaplib.py b/Lib/imaplib.py
--- a/Lib/imaplib.py
+++ b/Lib/imaplib.py
@@ -22,7 +22,7 @@

__version__ = "2.58"

-import binascii, errno, random, re, socket, subprocess, sys, time
+import binascii, errno, random, re, socket, subprocess, sys, time, calendar

try:
import ssl
@@ -1347,19 +1347,9 @@
zone = -zone

tt = (year, mon, day, hour, min, sec, -1, -1, -1)
+ utc = calendar.timegm(tt) - zone

- utc = time.mktime(tt)
-
- # Following is necessary because the time module has no 'mkgmtime'.
- # 'mktime' assumes arg in local timezone, so adds timezone/altzone.
-
- lt = time.localtime(utc)
- if time.daylight and lt[-1]:
- zone = zone + time.altzone
- else:
- zone = zone + time.timezone
-
- return time.localtime(utc - zone)
+ return time.localtime(utc)



diff --git a/Lib/test/support.py b/Lib/test/support.py
--- a/Lib/test/support.py
+++ b/Lib/test/support.py
@@ -57,7 +57,7 @@
"get_attribute", "swap_item", "swap_attr", "requires_IEEE_754",
"TestHandler", "Matcher", "can_symlink", "skip_unless_symlink",
"import_fresh_module", "requires_zlib", "PIPE_MAX_SIZE", "failfast",
- "anticipate_failure"
+ "anticipate_failure", "run_with_tz"
]

class Error(Exception):
@@ -1100,6 +1100,35 @@
return decorator

#=======================================================================
+# Decorator for running a function in a specific timezone, correctly
+# resetting it afterwards.
+
+def run_with_tz(tz):
+ def decorator(func):
+ def inner(*args, **kwds):
+ if 'TZ' in os.environ:
+ orig_tz = os.environ['TZ']
+ else:
+ orig_tz = None
+ os.environ['TZ'] = tz
+ time.tzset()
+
+ # now run the function, resetting the tz on exceptions
+ try:
+ return func(*args, **kwds)
+ finally:
+ if orig_tz == None:
+ del os.environ['TZ']
+ else:
+ os.environ['TZ'] = orig_tz
+ time.tzset()
+
+ inner.__name__ = func.__name__
+ inner.__doc__ = func.__doc__
+ return inner
+ return decorator
+
+#=======================================================================
# Big-memory-test support. Separate from 'resources' because memory use
# should be configurable.

diff --git a/Lib/test/test_imaplib.py b/Lib/test/test_imaplib.py
--- a/Lib/test/test_imaplib.py
+++ b/Lib/test/test_imaplib.py
@@ -11,7 +11,7 @@
import time
import calendar

-from test.support import reap_threads, verbose, transient_internet
+from test.support import reap_threads, verbose, transient_internet, run_with_tz
import unittest

try:
@@ -36,6 +36,13 @@
b'25 (INTERNALDATE "31-Dec-1999 12:30:00 -1130")')
self.assertEqual(time.mktime(tt), t0)

+ @run_with_tz('MST+07MDT,M4.1.0,M10.5.0')
+ def test_Internaldate2tuple_issue10941(self):
+ self.assertNotEqual(imaplib.Internaldate2tuple(
+ b'25 (INTERNALDATE "02-Apr-2000 02:30:00 +0000")'),
+ imaplib.Internaldate2tuple(
+ b'25 (INTERNALDATE "02-Apr-2000 03:30:00 +0000")'))
+
def test_that_Time2Internaldate_returns_a_result(self):
# We can check only that it successfully produces a result,
# not the correctness of the result itself, since the result
diff --git a/Misc/ACKS b/Misc/ACKS
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -770,6 +770,7 @@
Dan Parisien
Harri Pasanen
Gaël Pasgrimaud
+Joe Peterson
Randy Pausch
Samuele Pedroni
Marcel van der Peijl
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -84,6 +84,9 @@
Library
-------

+- Issue #10941: Fix imaplib.Internaldate2tuple to produce correct result near
+ the DST transition. Patch by Joe Peterson.
+
- Issue #9154: Fix parser module to understand function annotations.

- Issue #6085: In http.server.py SimpleHTTPServer.address_string returns the

--
Repository URL: http://hg.python.org/cpython
cpython (merge default -> default): merge [ In reply to ]
http://hg.python.org/cpython/rev/e393d83d6877
changeset: 76650:e393d83d6877
parent: 76649:2adcd28a5a3a
parent: 76648:5acddc7c666d
user: Raymond Hettinger <python@rcn.com>
date: Sun Apr 29 14:57:05 2012 -0700
summary:
merge

files:
Lib/imaplib.py | 16 ++--------
Lib/test/support.py | 31 ++++++++++++++++++++-
Lib/test/test_imaplib.py | 9 +++++-
Lib/test/test_parser.py | 10 ++++++
Misc/ACKS | 1 +
Misc/NEWS | 5 +++
Modules/parsermodule.c | 41 ++++++++++++++++++++++++---
7 files changed, 93 insertions(+), 20 deletions(-)


diff --git a/Lib/imaplib.py b/Lib/imaplib.py
--- a/Lib/imaplib.py
+++ b/Lib/imaplib.py
@@ -22,7 +22,7 @@

__version__ = "2.58"

-import binascii, errno, random, re, socket, subprocess, sys, time
+import binascii, errno, random, re, socket, subprocess, sys, time, calendar

try:
import ssl
@@ -1347,19 +1347,9 @@
zone = -zone

tt = (year, mon, day, hour, min, sec, -1, -1, -1)
+ utc = calendar.timegm(tt) - zone

- utc = time.mktime(tt)
-
- # Following is necessary because the time module has no 'mkgmtime'.
- # 'mktime' assumes arg in local timezone, so adds timezone/altzone.
-
- lt = time.localtime(utc)
- if time.daylight and lt[-1]:
- zone = zone + time.altzone
- else:
- zone = zone + time.timezone
-
- return time.localtime(utc - zone)
+ return time.localtime(utc)



diff --git a/Lib/test/support.py b/Lib/test/support.py
--- a/Lib/test/support.py
+++ b/Lib/test/support.py
@@ -57,7 +57,7 @@
"get_attribute", "swap_item", "swap_attr", "requires_IEEE_754",
"TestHandler", "Matcher", "can_symlink", "skip_unless_symlink",
"import_fresh_module", "requires_zlib", "PIPE_MAX_SIZE", "failfast",
- "anticipate_failure"
+ "anticipate_failure", "run_with_tz"
]

class Error(Exception):
@@ -1100,6 +1100,35 @@
return decorator

#=======================================================================
+# Decorator for running a function in a specific timezone, correctly
+# resetting it afterwards.
+
+def run_with_tz(tz):
+ def decorator(func):
+ def inner(*args, **kwds):
+ if 'TZ' in os.environ:
+ orig_tz = os.environ['TZ']
+ else:
+ orig_tz = None
+ os.environ['TZ'] = tz
+ time.tzset()
+
+ # now run the function, resetting the tz on exceptions
+ try:
+ return func(*args, **kwds)
+ finally:
+ if orig_tz == None:
+ del os.environ['TZ']
+ else:
+ os.environ['TZ'] = orig_tz
+ time.tzset()
+
+ inner.__name__ = func.__name__
+ inner.__doc__ = func.__doc__
+ return inner
+ return decorator
+
+#=======================================================================
# Big-memory-test support. Separate from 'resources' because memory use
# should be configurable.

diff --git a/Lib/test/test_imaplib.py b/Lib/test/test_imaplib.py
--- a/Lib/test/test_imaplib.py
+++ b/Lib/test/test_imaplib.py
@@ -11,7 +11,7 @@
import time
import calendar

-from test.support import reap_threads, verbose, transient_internet
+from test.support import reap_threads, verbose, transient_internet, run_with_tz
import unittest

try:
@@ -36,6 +36,13 @@
b'25 (INTERNALDATE "31-Dec-1999 12:30:00 -1130")')
self.assertEqual(time.mktime(tt), t0)

+ @run_with_tz('MST+07MDT,M4.1.0,M10.5.0')
+ def test_Internaldate2tuple_issue10941(self):
+ self.assertNotEqual(imaplib.Internaldate2tuple(
+ b'25 (INTERNALDATE "02-Apr-2000 02:30:00 +0000")'),
+ imaplib.Internaldate2tuple(
+ b'25 (INTERNALDATE "02-Apr-2000 03:30:00 +0000")'))
+
def test_that_Time2Internaldate_returns_a_result(self):
# We can check only that it successfully produces a result,
# not the correctness of the result itself, since the result
diff --git a/Lib/test/test_parser.py b/Lib/test/test_parser.py
--- a/Lib/test/test_parser.py
+++ b/Lib/test/test_parser.py
@@ -61,6 +61,16 @@
" if (yield):\n"
" yield x\n")

+ def test_nonlocal_statement(self):
+ self.check_suite("def f():\n"
+ " x = 0\n"
+ " def g():\n"
+ " nonlocal x\n")
+ self.check_suite("def f():\n"
+ " x = y = 0\n"
+ " def g():\n"
+ " nonlocal x, y\n")
+
def test_expressions(self):
self.check_expr("foo(1)")
self.check_expr("[1, 2, 3]")
diff --git a/Misc/ACKS b/Misc/ACKS
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -770,6 +770,7 @@
Dan Parisien
Harri Pasanen
Gaël Pasgrimaud
+Joe Peterson
Randy Pausch
Samuele Pedroni
Marcel van der Peijl
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -84,6 +84,11 @@
Library
-------

+- Issue #14696: Fix parser module to understand 'nonlocal' declarations.
+
+- Issue #10941: Fix imaplib.Internaldate2tuple to produce correct result near
+ the DST transition. Patch by Joe Peterson.
+
- Issue #9154: Fix parser module to understand function annotations.

- Issue #6085: In http.server.py SimpleHTTPServer.address_string returns the
diff --git a/Modules/parsermodule.c b/Modules/parsermodule.c
--- a/Modules/parsermodule.c
+++ b/Modules/parsermodule.c
@@ -956,7 +956,8 @@
VALIDATER(return_stmt); VALIDATER(raise_stmt);
VALIDATER(import_stmt); VALIDATER(import_stmt);
VALIDATER(import_name); VALIDATER(yield_stmt);
-VALIDATER(global_stmt); VALIDATER(assert_stmt);
+VALIDATER(global_stmt); VALIDATER(nonlocal_stmt);
+VALIDATER(assert_stmt);
VALIDATER(compound_stmt); VALIDATER(test_or_star_expr);
VALIDATER(while); VALIDATER(for);
VALIDATER(try); VALIDATER(except_clause);
@@ -1480,6 +1481,7 @@
|| (ntype == flow_stmt)
|| (ntype == import_stmt)
|| (ntype == global_stmt)
+ || (ntype == nonlocal_stmt)
|| (ntype == assert_stmt))
res = validate_node(CHILD(tree, 0));
else {
@@ -1864,8 +1866,10 @@
}


-
-
+/* global_stmt:
+ *
+ * 'global' NAME (',' NAME)*
+ */
static int
validate_global_stmt(node *tree)
{
@@ -1887,6 +1891,30 @@
return (res);
}

+/* nonlocal_stmt:
+ *
+ * 'nonlocal' NAME (',' NAME)*
+ */
+static int
+validate_nonlocal_stmt(node *tree)
+{
+ int j;
+ int nch = NCH(tree);
+ int res = (validate_ntype(tree, nonlocal_stmt)
+ && is_even(nch) && (nch >= 2));
+
+ if (!res && !PyErr_Occurred())
+ err_string("illegal nonlocal statement");
+
+ if (res)
+ res = (validate_name(CHILD(tree, 0), "nonlocal")
+ && validate_ntype(CHILD(tree, 1), NAME));
+ for (j = 2; res && (j < nch); j += 2)
+ res = (validate_comma(CHILD(tree, j))
+ && validate_ntype(CHILD(tree, j + 1), NAME));
+
+ return res;
+}

/* assert_stmt:
*
@@ -2951,8 +2979,8 @@
break;
case small_stmt:
/*
- * expr_stmt | del_stmt | pass_stmt | flow_stmt
- * | import_stmt | global_stmt | assert_stmt
+ * expr_stmt | del_stmt | pass_stmt | flow_stmt |
+ * import_stmt | global_stmt | nonlocal_stmt | assert_stmt
*/
res = validate_small_stmt(tree);
break;
@@ -3019,6 +3047,9 @@
case global_stmt:
res = validate_global_stmt(tree);
break;
+ case nonlocal_stmt:
+ res = validate_nonlocal_stmt(tree);
+ break;
case assert_stmt:
res = validate_assert_stmt(tree);
break;

--
Repository URL: http://hg.python.org/cpython
cpython (merge default -> default): merge [ In reply to ]
http://hg.python.org/cpython/rev/7319430a291d
changeset: 76659:7319430a291d
parent: 76658:08b54c635586
parent: 76656:d4fd58fff480
user: Victor Stinner <victor.stinner@gmail.com>
date: Mon Apr 30 05:24:04 2012 +0200
summary:
merge

files:
Doc/whatsnew/3.3.rst | 122 +++++++++++++++++++++++++++++++
Lib/functools.py | 21 ++--
2 files changed, 133 insertions(+), 10 deletions(-)


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
@@ -452,6 +452,89 @@
'<function C.D.meth at 0x7f46b9fe31e0>'


+Using importlib as the Implementation of Import
+===============================================
+:issue:`2377` - Replace __import__ w/ importlib.__import__
+:issue:`13959` - Re-implement parts of :mod:`imp` in pure Python
+:issue:`14605` - Make import machinery explicit
+:issue:`14646` - Require loaders set __loader__ and __package__
+
+(Written by Brett Cannon)
+
+The :func:`__import__` function is now powered by :func:`importlib.__import__`.
+This work leads to the completion of "phase 2" of :pep:`302`. There are
+multiple benefits to this change. First, it has allowed for more of the
+machinery powering import to be exposed instead of being implicit and hidden
+within the C code. It also provides a single implementation for all Python VMs
+supporting Python 3.3 to use, helping to end any VM-specific deviations in
+import semantics. And finally it eases the maintenance of import, allowing for
+future growth to occur.
+
+For the common user, this change should result in no visible change in
+semantics. Any possible changes required in one's code to handle this change
+should read the `Porting Python code`_ section of this document to see what
+needs to be changed, but it will only affect those that currently manipulate
+import or try calling it programmatically.
+
+New APIs
+--------
+One of the large benefits of this work is the exposure of what goes into
+making the import statement work. That means the various importers that were
+once implicit are now fully exposed as part of the :mod:`importlib` package.
+
+In terms of finders, * :class:`importlib.machinery.FileFinder` exposes the
+mechanism used to search for source and bytecode files of a module. Previously
+this class was an implicit member of :attr:`sys.path_hooks`.
+
+For loaders, the new abstract base class :class:`importlib.abc.FileLoader` helps
+write a loader that uses the file system as the storage mechanism for a module's
+code. The loader for source files
+(:class:`importlib.machinery.SourceFileLoader`), sourceless bytecode files
+(:class:`importlib.machinery.SourcelessFileLoader`), and extension modules
+(:class:`importlib.machinery.ExtensionFileLoader`) are now available for
+direct use.
+
+:exc:`ImportError` now has ``name`` and ``path`` attributes which are set when
+there is relevant data to provide. The message for failed imports will also
+provide the full name of the module now instead of just the tail end of the
+module's name.
+
+The :func:`importlib.invalidate_caches` function will now call the method with
+the same name on all finders cached in :attr:`sys.path_importer_cache` to help
+clean up any stored state as necessary.
+
+Visible Changes
+---------------
+[.For potential required changes to code, see the `Porting Python code`_
+section]
+
+Beyond the expanse of what :mod:`importlib` now exposes, there are other
+visible changes to import. The biggest is that :attr:`sys.meta_path` and
+:attr:`sys.path_hooks` now store all of the finders used by import explicitly.
+Previously the finders were implicit and hidden within the C code of import
+instead of being directly exposed. This means that one can now easily remove or
+change the order of the various finders to fit one's needs.
+
+Another change is that all modules have a ``__loader__`` attribute, storing the
+loader used to create the module. :pep:`302` has been updated to make this
+attribute mandatory for loaders to implement, so in the future once 3rd-party
+loaders have been updated people will be able to rely on the existence of the
+attribute. Until such time, though, import is setting the module post-load.
+
+Loaders are also now expected to set the ``__package__`` attribute from
+:pep:`366`. Once again, import itself is already setting this on all loaders
+from :mod:`importlib` and import itself is setting the attribute post-load.
+
+``None`` is now inserted into :attr:`sys.path_importer_cache` when no finder
+can be found on :attr:`sys.path_hooks`. Since :class:`imp.NullImporter` is not
+directly exposed on :attr:`sys.path_hooks` it could no longer be relied upon to
+always be available to use as a value representing no finder found.
+
+All other changes relate to semantic changes which should be taken into
+consideration when updating code for Python 3.3, and thus should be read about
+in the `Porting Python code`_ section of this document.
+
+
Other Language Changes
======================

@@ -1283,6 +1366,45 @@
timestamp is out of range. :exc:`OSError` is now raised if C functions
:c:func:`gmtime` or :c:func:`localtime` failed.

+* The default finders used by import now utilize a cache of what is contained
+ within a specific directory. If you create a Python source file or sourceless
+ bytecode file, make sure to call :func:`importlib.invalidate_caches` to clear
+ out the cache for the finders to notice the new file.
+
+* :exc:`ImportError` now uses the full name of the module that was attemped to
+ be imported. Doctests that check ImportErrors' message will need to be
+ updated to use the full name of the module instead of just the tail of the
+ name.
+
+* The **index** argument to :func:`__import__` now defaults to 0 instead of -1
+ and no longer support negative values. It was an oversight when :pep:`328` was
+ implemented that the default value remained -1. If you need to continue to
+ perform a relative import followed by an absolute import, then perform the
+ relative import using an index of 1, followed by another import using an
+ index of 0. It is preferred, though, that you use
+ :func:`importlib.import_module` rather than call :func:`__import__` directly.
+
+* :func:`__import__` no longer allows one to use an index value other than 0
+ for top-level modules. E.g. ``__import__('sys', level=1)`` is now an error.
+
+* Because :attr:`sys.meta_path` and :attr:`sys.path_hooks` now have finders on
+ them by default, you will most likely want to use :meth:`list.insert` instead
+ of :meth:`list.append` to add to those lists.
+
+* Because ``None`` is now inserted into :attr:`sys.path_importer_cache`, if you
+ are clearing out entries in the dictionary of paths that do not have a
+ finder, you will need to remove keys paired with values of ``None`` **and**
+ :class:`imp.NullImporter` to be backwards-compatible. This will need to extra
+ overhead on older versions of Python that re-insert ``None`` into
+ :attr:`sys.path_importer_cache` where it repesents the use of implicit
+ finders, but semantically it should not change anything.
+
+* :meth:`importlib.abc.SourceLoader.path_mtime` is now deprecated in favour of
+ :meth:`importlib.abc.SourceLoader.path_stats` as bytecode files now store
+ both the modification time and size of the source file the bytecode file was
+ compiled from.
+
+
Porting C code
--------------

diff --git a/Lib/functools.py b/Lib/functools.py
--- a/Lib/functools.py
+++ b/Lib/functools.py
@@ -168,15 +168,14 @@
# to allow the implementation to change (including a possible C version).

# Constants shared by all lru cache instances:
- kwd_mark = (object(),) # separate positional and keyword args
- sentinel = object() # unique object used to signal cache misses
- _len = len # localize the global len() function
+ kwd_mark = (object(),) # separate positional and keyword args
+ sentinel = object() # unique object used to signal cache misses
PREV, NEXT, KEY, RESULT = 0, 1, 2, 3 # names for the link fields

def decorating_function(user_function):

cache = {}
- hits = misses = 0
+ hits = misses = currsize = 0
cache_get = cache.get # bound method to lookup a key or return None
lock = Lock() # because linkedlist updates aren't threadsafe
root = [] # root of the circular doubly linked list
@@ -209,7 +208,7 @@

def wrapper(*args, **kwds):
# simple caching without ordering or size limit
- nonlocal hits, misses
+ nonlocal hits, misses, currsize
key = make_key(args, kwds, typed) if kwds or typed else args
result = cache_get(key, sentinel)
if result is not sentinel:
@@ -218,13 +217,14 @@
result = user_function(*args, **kwds)
cache[key] = result
misses += 1
+ currsize += 1
return result

else:

def wrapper(*args, **kwds):
# size limited caching that tracks accesses by recency
- nonlocal root, hits, misses
+ nonlocal root, hits, misses, currsize
key = make_key(args, kwds, typed) if kwds or typed else args
with lock:
link = cache_get(key)
@@ -241,11 +241,12 @@
return result
result = user_function(*args, **kwds)
with lock:
- if _len(cache) < maxsize:
+ if currsize < maxsize:
# put result in a new link at the front of the queue
last = root[PREV]
link = [last, root, key, result]
cache[key] = last[NEXT] = root[PREV] = link
+ currsize += 1
else:
# use root to store the new key and result
root[KEY] = key
@@ -261,15 +262,15 @@
def cache_info():
"""Report cache statistics"""
with lock:
- return _CacheInfo(hits, misses, maxsize, len(cache))
+ return _CacheInfo(hits, misses, maxsize, currsize)

def cache_clear():
"""Clear the cache and cache statistics"""
- nonlocal hits, misses
+ nonlocal hits, misses, currsize
with lock:
cache.clear()
root[:] = [root, root, None, None]
- hits = misses = 0
+ hits = misses = currsize = 0

wrapper.cache_info = cache_info
wrapper.cache_clear = cache_clear

--
Repository URL: http://hg.python.org/cpython
cpython (merge default -> default): merge [ In reply to ]
http://hg.python.org/cpython/rev/20f8b105525e
changeset: 76759:20f8b105525e
parent: 76758:7fbb4443ffb7
parent: 76756:4459d82ff127
user: Brett Cannon <brett@python.org>
date: Fri May 04 16:04:59 2012 -0400
summary:
merge

files:
PCbuild/make_buildinfo.c | 67 +++++++++++++++++++++++++++-
1 files changed, 66 insertions(+), 1 deletions(-)


diff --git a/PCbuild/make_buildinfo.c b/PCbuild/make_buildinfo.c
--- a/PCbuild/make_buildinfo.c
+++ b/PCbuild/make_buildinfo.c
@@ -2,6 +2,7 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
+#include <io.h>

#define CMD_SIZE 500

@@ -61,6 +62,51 @@
return 1;
}

+const char DELIMS[] = { " \n" };
+
+int get_mercurial_info(char * hgbranch, char * hgtag, char * hgrev, int size)
+{
+ int result = 0;
+ char filename[CMD_SIZE];
+ char cmdline[CMD_SIZE];
+
+ strcpy_s(filename, CMD_SIZE, "tmpXXXXXX");
+ if (_mktemp_s(filename, CMD_SIZE) == 0) {
+ int rc;
+
+ strcpy_s(cmdline, CMD_SIZE, "hg id -bit > ");
+ strcat_s(cmdline, CMD_SIZE, filename);
+ rc = system(cmdline);
+ if (rc == 0) {
+ FILE * fp;
+
+ if (fopen_s(&fp, filename, "r") == 0) {
+ char * cp = fgets(cmdline, CMD_SIZE, fp);
+
+ if (cp) {
+ char * context = NULL;
+ char * tp = strtok_s(cp, DELIMS, &context);
+ if (tp) {
+ strcpy_s(hgrev, size, tp);
+ tp = strtok_s(NULL, DELIMS, &context);
+ if (tp) {
+ strcpy_s(hgbranch, size, tp);
+ tp = strtok_s(NULL, DELIMS, &context);
+ if (tp) {
+ strcpy_s(hgtag, size, tp);
+ result = 1;
+ }
+ }
+ }
+ }
+ fclose(fp);
+ }
+ }
+ _unlink(filename);
+ }
+ return result;
+}
+
int main(int argc, char*argv[])
{
char command[CMD_SIZE] = "cl.exe -c -D_WIN32 -DUSE_DL_EXPORT -D_WINDOWS -DWIN32 -D_WINDLL ";
@@ -109,8 +155,27 @@
strcat_s(command, CMD_SIZE, "\"");
strcat_s(command, CMD_SIZE, tmppath);
strcat_s(command, CMD_SIZE, "getbuildinfo2.c\" -DSUBWCREV ");
- } else
+ }
+ else {
+ char hgtag[CMD_SIZE];
+ char hgbranch[CMD_SIZE];
+ char hgrev[CMD_SIZE];
+
+ if (get_mercurial_info(hgbranch, hgtag, hgrev, CMD_SIZE)) {
+ strcat_s(command, CMD_SIZE, "-DHGBRANCH=\\\"");
+ strcat_s(command, CMD_SIZE, hgbranch);
+ strcat_s(command, CMD_SIZE, "\\\"");
+
+ strcat_s(command, CMD_SIZE, " -DHGTAG=\\\"");
+ strcat_s(command, CMD_SIZE, hgtag);
+ strcat_s(command, CMD_SIZE, "\\\"");
+
+ strcat_s(command, CMD_SIZE, " -DHGVERSION=\\\"");
+ strcat_s(command, CMD_SIZE, hgrev);
+ strcat_s(command, CMD_SIZE, "\\\" ");
+ }
strcat_s(command, CMD_SIZE, "..\\Modules\\getbuildinfo.c");
+ }
strcat_s(command, CMD_SIZE, " -Fo\"");
strcat_s(command, CMD_SIZE, tmppath);
strcat_s(command, CMD_SIZE, "getbuildinfo.o\" -I..\\Include -I..\\PC");

--
Repository URL: http://hg.python.org/cpython
cpython (merge default -> default): Merge [ In reply to ]
http://hg.python.org/cpython/rev/5b2f40ed32fd
changeset: 76763:5b2f40ed32fd
parent: 76762:5bcce348571e
parent: 76761:06944dad6098
user: Antoine Pitrou <solipsis@pitrou.net>
date: Fri May 04 22:16:09 2012 +0200
summary:
Merge

files:
Python/import.c | 22 ----------------------
Python/importdl.h | 15 ---------------
2 files changed, 0 insertions(+), 37 deletions(-)


diff --git a/Python/import.c b/Python/import.c
--- a/Python/import.c
+++ b/Python/import.c
@@ -2091,17 +2091,6 @@
{NULL, NULL} /* sentinel */
};

-static int
-setint(PyObject *d, char *name, int value)
-{
- PyObject *v;
- int err;
-
- v = PyLong_FromLong((long)value);
- err = PyDict_SetItemString(d, name, v);
- Py_XDECREF(v);
- return err;
-}

static struct PyModuleDef impmodule = {
PyModuleDef_HEAD_INIT,
@@ -2127,17 +2116,6 @@
if (d == NULL)
goto failure;

- if (setint(d, "SEARCH_ERROR", SEARCH_ERROR) < 0) goto failure;
- if (setint(d, "PY_SOURCE", PY_SOURCE) < 0) goto failure;
- if (setint(d, "PY_COMPILED", PY_COMPILED) < 0) goto failure;
- if (setint(d, "C_EXTENSION", C_EXTENSION) < 0) goto failure;
- if (setint(d, "PY_RESOURCE", PY_RESOURCE) < 0) goto failure;
- if (setint(d, "PKG_DIRECTORY", PKG_DIRECTORY) < 0) goto failure;
- if (setint(d, "C_BUILTIN", C_BUILTIN) < 0) goto failure;
- if (setint(d, "PY_FROZEN", PY_FROZEN) < 0) goto failure;
- if (setint(d, "PY_CODERESOURCE", PY_CODERESOURCE) < 0) goto failure;
- if (setint(d, "IMP_HOOK", IMP_HOOK) < 0) goto failure;
-
return m;
failure:
Py_XDECREF(m);
diff --git a/Python/importdl.h b/Python/importdl.h
--- a/Python/importdl.h
+++ b/Python/importdl.h
@@ -6,21 +6,6 @@
#endif


-/* Definitions for dynamic loading of extension modules */
-enum filetype {
- SEARCH_ERROR,
- PY_SOURCE,
- PY_COMPILED,
- C_EXTENSION,
- PY_RESOURCE, /* Mac only */
- PKG_DIRECTORY,
- C_BUILTIN,
- PY_FROZEN,
- PY_CODERESOURCE, /* Mac only */
- IMP_HOOK
-};
-
-
extern const char *_PyImport_DynLoadFiletab[];

extern PyObject *_PyImport_LoadDynamicModule(PyObject *name, PyObject *pathname,

--
Repository URL: http://hg.python.org/cpython
cpython (merge default -> default): Merge [ In reply to ]
http://hg.python.org/cpython/rev/57cbffae4f74
changeset: 76767:57cbffae4f74
parent: 76766:66ccd993dfdf
parent: 76765:146001e3364d
user: Antoine Pitrou <solipsis@pitrou.net>
date: Fri May 04 23:17:03 2012 +0200
summary:
Merge

files:
Lib/importlib/_bootstrap.py | 7 +------
Python/importlib.h | Bin
2 files changed, 1 insertions(+), 6 deletions(-)


diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py
--- a/Lib/importlib/_bootstrap.py
+++ b/Lib/importlib/_bootstrap.py
@@ -1151,12 +1151,7 @@


def _install(sys_module, _imp_module):
- """Install importlib as the implementation of import.
-
- It is assumed that _imp and sys have been imported and injected into the
- global namespace for the module prior to calling this function.
-
- """
+ """Install importlib as the implementation of import."""
_setup(sys_module, _imp_module)
extensions = ExtensionFileLoader, _imp_module.extension_suffixes(), False
source = SourceFileLoader, _SOURCE_SUFFIXES, True
diff --git a/Python/importlib.h b/Python/importlib.h
index 9c531f013f45b202d3523994af2799d4270339a7..292308fc78123e9fa10c7131bb110c47559975dd
GIT binary patch
[stripped]

--
Repository URL: http://hg.python.org/cpython
cpython (merge default -> default): Merge [ In reply to ]
http://hg.python.org/cpython/rev/3b368c4ad7c5
changeset: 76884:3b368c4ad7c5
parent: 76883:85824b819bcb
parent: 76882:9d9495fabeb9
user: Antoine Pitrou <solipsis@pitrou.net>
date: Sat May 12 19:02:47 2012 +0200
summary:
Merge

files:
Objects/unicodeobject.c | 14 ++++++++++----
1 files changed, 10 insertions(+), 4 deletions(-)


diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c
--- a/Objects/unicodeobject.c
+++ b/Objects/unicodeobject.c
@@ -9075,12 +9075,15 @@

kind1 = PyUnicode_KIND(str_obj);
kind2 = PyUnicode_KIND(sub_obj);
- kind = kind2;
+ kind = kind1;
buf1 = PyUnicode_DATA(str_obj);
buf2 = PyUnicode_DATA(sub_obj);
if (kind2 != kind) {
- if (kind2 > kind)
- return 0;
+ if (kind2 > kind) {
+ Py_DECREF(sub_obj);
+ Py_DECREF(str_obj);
+ return 0;
+ }
buf2 = _PyUnicode_AsKind(sub_obj, kind);
}
if (!buf2)
@@ -10659,8 +10662,11 @@
buf1 = PyUnicode_DATA(str);
buf2 = PyUnicode_DATA(sub);
if (kind2 != kind) {
- if (kind2 > kind)
+ if (kind2 > kind) {
+ Py_DECREF(sub);
+ Py_DECREF(str);
return 0;
+ }
buf2 = _PyUnicode_AsKind(sub, kind);
}
if (!buf2) {

--
Repository URL: http://hg.python.org/cpython
cpython (merge default -> default): Merge [ In reply to ]
http://hg.python.org/cpython/rev/964cfda9ccc5
changeset: 76893:964cfda9ccc5
parent: 76892:10e8b97d0fd7
parent: 76889:8d85f9920878
user: Antoine Pitrou <solipsis@pitrou.net>
date: Sat May 12 23:43:55 2012 +0200
summary:
Merge

files:
Lib/test/test_shutil.py | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)


diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py
--- a/Lib/test/test_shutil.py
+++ b/Lib/test/test_shutil.py
@@ -343,7 +343,7 @@
orig_setxattr = os.setxattr
os.setxattr = _raise_on_user_foo
shutil._copyxattr(src, dst)
- self.assertEqual(['user.bar'], os.listxattr(dst))
+ self.assertIn('user.bar', os.listxattr(dst))
finally:
os.setxattr = orig_setxattr


--
Repository URL: http://hg.python.org/cpython
cpython (merge default -> default): Merge [ In reply to ]
http://hg.python.org/cpython/rev/5bd55fb3e091
changeset: 76894:5bd55fb3e091
parent: 76893:964cfda9ccc5
parent: 76891:7bf8ac742d2f
user: Antoine Pitrou <solipsis@pitrou.net>
date: Sat May 12 23:44:59 2012 +0200
summary:
Merge

files:
Doc/library/importlib.rst | 14 ++++++
Lib/importlib/__init__.py | 24 ++++++++++
Lib/importlib/test/test_api.py | 50 +++++++++++++++++++++-
Lib/pyclbr.py | 25 +++++++---
Lib/test/test_unicode.py | 8 ---
Misc/NEWS | 2 +
6 files changed, 105 insertions(+), 18 deletions(-)


diff --git a/Doc/library/importlib.rst b/Doc/library/importlib.rst
--- a/Doc/library/importlib.rst
+++ b/Doc/library/importlib.rst
@@ -86,6 +86,20 @@
that was imported (e.g. ``pkg.mod``), while :func:`__import__` returns the
top-level package or module (e.g. ``pkg``).

+.. function:: find_loader(name, path=None)
+
+ Find the loader for a module, optionally within the specified *path*. If the
+ module is in :attr:`sys.modules`, then ``sys.modules[name].__loader__`` is
+ returned (unless the loader would be ``None``, in which case
+ :exc:`ValueError` is raised). Otherwise a search using :attr:`sys.meta_path`
+ is done. ``None`` is returned if no loader is found.
+
+ A dotted name does not have its parent's implicitly imported. If that is
+ desired (although not nessarily required to find the loader, it will most
+ likely be needed if the loader actually is used to load the module), then
+ you will have to import the packages containing the module prior to calling
+ this function.
+
.. function:: invalidate_caches()

Invalidate the internal caches of the finders stored at
diff --git a/Lib/importlib/__init__.py b/Lib/importlib/__init__.py
--- a/Lib/importlib/__init__.py
+++ b/Lib/importlib/__init__.py
@@ -29,6 +29,30 @@
finder.invalidate_caches()


+def find_loader(name, path=None):
+ """Find the loader for the specified module.
+
+ First, sys.modules is checked to see if the module was already imported. If
+ so, then sys.modules[name].__loader__ is returned. If that happens to be
+ set to None, then ValueError is raised. If the module is not in
+ sys.modules, then sys.meta_path is searched for a suitable loader with the
+ value of 'path' given to the finders. None is returned if no loader could
+ be found.
+
+ Dotted names do not have their parent packages implicitly imported.
+
+ """
+ try:
+ loader = sys.modules[name].__loader__
+ if loader is None:
+ raise ValueError('{}.__loader__ is None'.format(name))
+ else:
+ return loader
+ except KeyError:
+ pass
+ return _bootstrap._find_module(name, path)
+
+
def import_module(name, package=None):
"""Import a module.

diff --git a/Lib/importlib/test/test_api.py b/Lib/importlib/test/test_api.py
--- a/Lib/importlib/test/test_api.py
+++ b/Lib/importlib/test/test_api.py
@@ -85,6 +85,54 @@
self.assertEqual(b_load_count, 1)


+class FindLoaderTests(unittest.TestCase):
+
+ class FakeMetaFinder:
+ @staticmethod
+ def find_module(name, path=None): return name, path
+
+ def test_sys_modules(self):
+ # If a module with __loader__ is in sys.modules, then return it.
+ name = 'some_mod'
+ with util.uncache(name):
+ module = imp.new_module(name)
+ loader = 'a loader!'
+ module.__loader__ = loader
+ sys.modules[name] = module
+ found = importlib.find_loader(name)
+ self.assertEqual(loader, found)
+
+ def test_sys_modules_loader_is_None(self):
+ # If sys.modules[name].__loader__ is None, raise ValueError.
+ name = 'some_mod'
+ with util.uncache(name):
+ module = imp.new_module(name)
+ module.__loader__ = None
+ sys.modules[name] = module
+ with self.assertRaises(ValueError):
+ importlib.find_loader(name)
+
+ def test_success(self):
+ # Return the loader found on sys.meta_path.
+ name = 'some_mod'
+ with util.uncache(name):
+ with util.import_state(meta_path=[self.FakeMetaFinder]):
+ self.assertEqual((name, None), importlib.find_loader(name))
+
+ def test_success_path(self):
+ # Searching on a path should work.
+ name = 'some_mod'
+ path = 'path to some place'
+ with util.uncache(name):
+ with util.import_state(meta_path=[self.FakeMetaFinder]):
+ self.assertEqual((name, path),
+ importlib.find_loader(name, path))
+
+ def test_nothing(self):
+ # None is returned upon failure to find a loader.
+ self.assertIsNone(importlib.find_loader('nevergoingtofindthismodule'))
+
+
class InvalidateCacheTests(unittest.TestCase):

def test_method_called(self):
@@ -114,7 +162,7 @@

def test_main():
from test.support import run_unittest
- run_unittest(ImportModuleTests)
+ run_unittest(ImportModuleTests, FindLoaderTests, InvalidateCacheTests)


if __name__ == '__main__':
diff --git a/Lib/pyclbr.py b/Lib/pyclbr.py
--- a/Lib/pyclbr.py
+++ b/Lib/pyclbr.py
@@ -39,8 +39,10 @@
lineno -- the line in the file on which the class statement occurred
"""

+import io
+import os
import sys
-import imp
+import importlib
import tokenize
from token import NAME, DEDENT, OP
from operator import itemgetter
@@ -133,19 +135,24 @@
# Search the path for the module
f = None
if inpackage is not None:
- f, fname, (_s, _m, ty) = imp.find_module(module, path)
+ search_path = path
else:
- f, fname, (_s, _m, ty) = imp.find_module(module, path + sys.path)
- if ty == imp.PKG_DIRECTORY:
- dict['__path__'] = [fname]
- path = [fname] + path
- f, fname, (_s, _m, ty) = imp.find_module('__init__', [fname])
+ search_path = path + sys.path
+ loader = importlib.find_loader(fullmodule, search_path)
+ fname = loader.get_filename(fullmodule)
_modules[fullmodule] = dict
- if ty != imp.PY_SOURCE:
+ if loader.is_package(fullmodule):
+ dict['__path__'] = [os.path.dirname(fname)]
+ try:
+ source = loader.get_source(fullmodule)
+ if source is None:
+ return dict
+ except (AttributeError, ImportError):
# not Python source, can't do anything with this module
- f.close()
return dict

+ f = io.StringIO(source)
+
stack = [] # stack of (class, indent) pairs

g = tokenize.generate_tokens(f.readline)
diff --git a/Lib/test/test_unicode.py b/Lib/test/test_unicode.py
--- a/Lib/test/test_unicode.py
+++ b/Lib/test/test_unicode.py
@@ -1422,14 +1422,6 @@
self.assertRaises(TypeError, str, b"hello", "test.unicode2")
self.assertRaises(TypeError, "hello".encode, "test.unicode1")
self.assertRaises(TypeError, "hello".encode, "test.unicode2")
- # executes PyUnicode_Encode()
- import imp
- self.assertRaises(
- ImportError,
- imp.find_module,
- "non-existing module",
- ["non-existing dir"]
- )

# Error handling (wrong arguments)
self.assertRaises(TypeError, "hello".encode, 42, 42, 42)
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -23,6 +23,8 @@
Library
-------

+- Issue #13959: Introduce importlib.find_loader().
+
- Issue #14082: shutil.copy2() now copies extended attributes, if possible.
Patch by Hynek Schlawack.


--
Repository URL: http://hg.python.org/cpython
cpython (merge default -> default): Merge [ In reply to ]
http://hg.python.org/cpython/rev/8e3425396912
changeset: 77017:8e3425396912
parent: 77016:423a26e8ffbb
parent: 77015:c62fa6892424
user: Antoine Pitrou <solipsis@pitrou.net>
date: Thu May 17 21:04:49 2012 +0200
summary:
Merge

files:
Lib/tarfile.py | 4 ++--
Misc/ACKS | 1 +
Misc/NEWS | 3 +++
3 files changed, 6 insertions(+), 2 deletions(-)


diff --git a/Lib/tarfile.py b/Lib/tarfile.py
--- a/Lib/tarfile.py
+++ b/Lib/tarfile.py
@@ -245,8 +245,8 @@
the high bit set. So we calculate two checksums, unsigned and
signed.
"""
- unsigned_chksum = 256 + sum(struct.unpack("148B", buf[:148]) + struct.unpack("356B", buf[156:512]))
- signed_chksum = 256 + sum(struct.unpack("148b", buf[:148]) + struct.unpack("356b", buf[156:512]))
+ unsigned_chksum = 256 + sum(struct.unpack_from("148B8x356B", buf))
+ signed_chksum = 256 + sum(struct.unpack_from("148b8x356b", buf))
return unsigned_chksum, signed_chksum

def copyfileobj(src, dst, length=None):
diff --git a/Misc/ACKS b/Misc/ACKS
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -776,6 +776,7 @@
Joe Peterson
Randy Pausch
Samuele Pedroni
+Justin Peel
Marcel van der Peijl
Berker Peksag
Steven Pemberton
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -38,6 +38,9 @@
Library
-------

+- Issue #13031: Small speed-up for tarfile when unzipping tarfiles.
+ Patch by Justin Peel.
+
- Issue #14780: urllib.request.urlopen() now has a ``cadefault`` argument
to use the default certificate store. Initial patch by James Oakley.


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