From python-checkins at python.org Fri Apr 1 00:46:54 2011 From: python-checkins at python.org (raymond.hettinger) Date: Fri, 01 Apr 2011 00:46:54 +0200 Subject: [Python-checkins] cpython (3.2): Issue #7796: Add link to Jan Kaliszewski's alternate constructor and ABC for Message-ID: http://hg.python.org/cpython/rev/7aa3f1f7ac94 changeset: 69093:7aa3f1f7ac94 branch: 3.2 parent: 69091:9797bfe8240f user: Raymond Hettinger date: Thu Mar 31 15:46:06 2011 -0700 summary: Issue #7796: Add link to Jan Kaliszewski's alternate constructor and ABC for named tuples. files: Doc/library/collections.rst | 11 +++++++++-- Misc/ACKS | 1 + 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/Doc/library/collections.rst b/Doc/library/collections.rst --- a/Doc/library/collections.rst +++ b/Doc/library/collections.rst @@ -775,8 +775,15 @@ .. seealso:: - `Named tuple recipe `_ - adapted for Python 2.4. + * `Named tuple recipe `_ + adapted for Python 2.4. + + * `Recipe for named tuple abstract base class with a metaclass mix-in + `_ + by Jan Kaliszewski. Besides providing an :term:`abstract base class` for + named tuples, it also supports an alternate :term:`metaclass`-based + constructor that is convenient for use cases where named tuples are being + subclassed. :class:`OrderedDict` objects diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -449,6 +449,7 @@ Peter van Kampen Rafe Kaplan Jacob Kaplan-Moss +Jan Kaliszewski Arkady Koplyarov Lou Kates Hiroaki Kawai -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 1 00:46:56 2011 From: python-checkins at python.org (raymond.hettinger) Date: Fri, 01 Apr 2011 00:46:56 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Issue #7796: Add link to Jan Kaliszewski's alternate constructor and ABC for Message-ID: http://hg.python.org/cpython/rev/330d3482cad8 changeset: 69094:330d3482cad8 parent: 69092:3e191db416a6 parent: 69093:7aa3f1f7ac94 user: Raymond Hettinger date: Thu Mar 31 15:46:39 2011 -0700 summary: Issue #7796: Add link to Jan Kaliszewski's alternate constructor and ABC for named tuples. files: Doc/library/collections.rst | 11 +++++++++-- Misc/ACKS | 1 + 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/Doc/library/collections.rst b/Doc/library/collections.rst --- a/Doc/library/collections.rst +++ b/Doc/library/collections.rst @@ -857,8 +857,15 @@ .. seealso:: - `Named tuple recipe `_ - adapted for Python 2.4. + * `Named tuple recipe `_ + adapted for Python 2.4. + + * `Recipe for named tuple abstract base class with a metaclass mix-in + `_ + by Jan Kaliszewski. Besides providing an :term:`abstract base class` for + named tuples, it also supports an alternate :term:`metaclass`-based + constructor that is convenient for use cases where named tuples are being + subclassed. :class:`OrderedDict` objects diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -452,6 +452,7 @@ Peter van Kampen Rafe Kaplan Jacob Kaplan-Moss +Jan Kaliszewski Arkady Koplyarov Lou Kates Hiroaki Kawai -- Repository URL: http://hg.python.org/cpython From tjreedy at udel.edu Fri Apr 1 01:44:12 2011 From: tjreedy at udel.edu (Terry Reedy) Date: Thu, 31 Mar 2011 19:44:12 -0400 Subject: [Python-checkins] cpython (3.2): Add links to make the math docs more usable. In-Reply-To: <4D94D2A8.3000405@gmail.com> References: <4D94D2A8.3000405@gmail.com> Message-ID: <4D9511CC.3010901@udel.edu> >> + Return the `Gamma function` at *x*. >> > > There's a space missing here, and the link doesn't work. It does for me. This may depend on the mail reader and whether it parses the url out in spite of the missing space. From python-checkins at python.org Fri Apr 1 02:31:31 2011 From: python-checkins at python.org (victor.stinner) Date: Fri, 01 Apr 2011 02:31:31 +0200 Subject: [Python-checkins] cpython: Issue #11393: Fix faulthandler_thread(): release cancel lock before join lock Message-ID: http://hg.python.org/cpython/rev/8b1341d51fe6 changeset: 69095:8b1341d51fe6 user: Victor Stinner date: Fri Apr 01 02:28:22 2011 +0200 summary: Issue #11393: Fix faulthandler_thread(): release cancel lock before join lock If the thread releases the join lock before the cancel lock, the thread may sometimes still be alive at cancel_dump_tracebacks_later() exit. So the cancel lock may be destroyed while the thread is still alive, whereas the thread will try to release the cancel lock, which just crash. Another minor fix: the thread doesn't release the cancel lock if it didn't acquire it. files: Modules/faulthandler.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Modules/faulthandler.c b/Modules/faulthandler.c --- a/Modules/faulthandler.c +++ b/Modules/faulthandler.c @@ -401,6 +401,7 @@ thread.timeout_ms, 0); if (st == PY_LOCK_ACQUIRED) { /* Cancelled by user */ + PyThread_release_lock(thread.cancel_event); break; } /* Timeout => dump traceback */ @@ -419,7 +420,6 @@ /* The only way out */ thread.running = 0; PyThread_release_lock(thread.join_event); - PyThread_release_lock(thread.cancel_event); } static void -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 1 03:00:21 2011 From: python-checkins at python.org (victor.stinner) Date: Fri, 01 Apr 2011 03:00:21 +0200 Subject: [Python-checkins] cpython: Issue #11393: New try to fix faulthandler_thread() Message-ID: http://hg.python.org/cpython/rev/0fb0fbd442b4 changeset: 69096:0fb0fbd442b4 user: Victor Stinner date: Fri Apr 01 03:00:05 2011 +0200 summary: Issue #11393: New try to fix faulthandler_thread() Always release the cancel join. Fix also another corner case: _PyFaulthandler_Fini() called after setting running variable to zero, but before releasing the join lock. files: Modules/faulthandler.c | 12 ++++++------ 1 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Modules/faulthandler.c b/Modules/faulthandler.c --- a/Modules/faulthandler.c +++ b/Modules/faulthandler.c @@ -401,7 +401,6 @@ thread.timeout_ms, 0); if (st == PY_LOCK_ACQUIRED) { /* Cancelled by user */ - PyThread_release_lock(thread.cancel_event); break; } /* Timeout => dump traceback */ @@ -418,8 +417,9 @@ } while (ok && thread.repeat); /* The only way out */ + PyThread_release_lock(thread.cancel_event); + PyThread_release_lock(thread.join_event); thread.running = 0; - PyThread_release_lock(thread.join_event); } static void @@ -428,11 +428,11 @@ if (thread.running) { /* Notify cancellation */ PyThread_release_lock(thread.cancel_event); - /* Wait for thread to join */ - PyThread_acquire_lock(thread.join_event, 1); - assert(thread.running == 0); - PyThread_release_lock(thread.join_event); } + /* Wait for thread to join */ + PyThread_acquire_lock(thread.join_event, 1); + assert(thread.running == 0); + PyThread_release_lock(thread.join_event); Py_CLEAR(thread.file); } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 1 03:17:36 2011 From: python-checkins at python.org (victor.stinner) Date: Fri, 01 Apr 2011 03:17:36 +0200 Subject: [Python-checkins] cpython: Issue #11393: fix usage of locks in faulthandler Message-ID: http://hg.python.org/cpython/rev/3558eecd84f0 changeset: 69097:3558eecd84f0 user: Victor Stinner date: Fri Apr 01 03:16:51 2011 +0200 summary: Issue #11393: fix usage of locks in faulthandler * faulthandler_cancel_dump_tracebacks_later() is responsible to set running to zero (so we don't need the volatile keyword anymore) * release locks if PyThread_start_new_thread() fails assert(thread.running == 0) was wrong in a corner case files: Modules/faulthandler.c | 7 ++++--- 1 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Modules/faulthandler.c b/Modules/faulthandler.c --- a/Modules/faulthandler.c +++ b/Modules/faulthandler.c @@ -48,7 +48,7 @@ int fd; PY_TIMEOUT_T timeout_ms; /* timeout in microseconds */ int repeat; - volatile int running; + int running; PyInterpreterState *interp; int exit; /* released by parent thread when cancel request */ @@ -419,7 +419,6 @@ /* The only way out */ PyThread_release_lock(thread.cancel_event); PyThread_release_lock(thread.join_event); - thread.running = 0; } static void @@ -431,8 +430,8 @@ } /* Wait for thread to join */ PyThread_acquire_lock(thread.join_event, 1); - assert(thread.running == 0); PyThread_release_lock(thread.join_event); + thread.running = 0; Py_CLEAR(thread.file); } @@ -486,6 +485,8 @@ thread.running = 1; if (PyThread_start_new_thread(faulthandler_thread, NULL) == -1) { thread.running = 0; + PyThread_release_lock(thread.join_event); + PyThread_release_lock(thread.cancel_event); Py_CLEAR(thread.file); PyErr_SetString(PyExc_RuntimeError, "unable to start watchdog thread"); -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Fri Apr 1 04:55:16 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Fri, 01 Apr 2011 04:55:16 +0200 Subject: [Python-checkins] Daily reference leaks (3558eecd84f0): sum=0 Message-ID: results for 3558eecd84f0 on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogYX7SDN', '-x'] From python-checkins at python.org Fri Apr 1 09:20:17 2011 From: python-checkins at python.org (georg.brandl) Date: Fri, 01 Apr 2011 09:20:17 +0200 Subject: [Python-checkins] cpython: Fix markup. Message-ID: http://hg.python.org/cpython/rev/214d0608fb84 changeset: 69098:214d0608fb84 user: Georg Brandl date: Fri Apr 01 09:19:57 2011 +0200 summary: Fix markup. files: Doc/library/faulthandler.rst | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/faulthandler.rst b/Doc/library/faulthandler.rst --- a/Doc/library/faulthandler.rst +++ b/Doc/library/faulthandler.rst @@ -69,8 +69,8 @@ Dump the tracebacks of all threads, after a timeout of *timeout* seconds, or each *timeout* seconds if *repeat* is ``True``. If *exit* is True, call - :cfunc:`_exit` with status=1 after dumping the tracebacks to terminate - immediatly the process, which is not safe. For example, :cfunc:`_exit` + :c:func:`_exit` with status=1 after dumping the tracebacks to terminate + immediatly the process, which is not safe. For example, :c:func:`_exit` doesn't flush file buffers. If the function is called twice, the new call replaces previous parameters (resets the timeout). The timer has a sub-second resolution. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 1 12:14:28 2011 From: python-checkins at python.org (victor.stinner) Date: Fri, 01 Apr 2011 12:14:28 +0200 Subject: [Python-checkins] cpython: Issue #11393: fault handler uses raise(signum) for SIGILL on Windows Message-ID: http://hg.python.org/cpython/rev/e51d8a160a8a changeset: 69099:e51d8a160a8a user: Victor Stinner date: Fri Apr 01 12:08:57 2011 +0200 summary: Issue #11393: fault handler uses raise(signum) for SIGILL on Windows files: Modules/faulthandler.c | 27 ++++++++++++--------------- 1 files changed, 12 insertions(+), 15 deletions(-) diff --git a/Modules/faulthandler.c b/Modules/faulthandler.c --- a/Modules/faulthandler.c +++ b/Modules/faulthandler.c @@ -270,14 +270,16 @@ else _Py_DumpTraceback(fd, tstate); -#ifndef MS_WINDOWS - /* call the previous signal handler: it is called if we use sigaction() - thanks to SA_NODEFER flag, otherwise it is deferred */ +#ifdef MS_WINDOWS + if (signum == SIGSEGV) { + /* don't call explictly the previous handler for SIGSEGV in this signal + handler, because the Windows signal handler would not be called */ + return; + } +#endif + /* call the previous signal handler: it is called immediatly if we use + sigaction() thanks to SA_NODEFER flag, otherwise it is deferred */ raise(signum); -#else - /* on Windows, don't call explictly the previous handler, because Windows - signal handler would not be called */ -#endif } /* Install handler for fatal signals (SIGSEGV, SIGFPE, ...). */ @@ -681,8 +683,9 @@ faulthandler_sigsegv(PyObject *self, PyObject *args) { #if defined(MS_WINDOWS) - /* faulthandler_fatal_error() restores the previous signal handler and then - gives back the execution flow to the program. In a normal case, the + /* For SIGSEGV, faulthandler_fatal_error() restores the previous signal + handler and then gives back the execution flow to the program (without + calling explicitly the previous error handler). In a normal case, the SIGSEGV was raised by the kernel because of a fault, and so if the program retries to execute the same instruction, the fault will be raised again. @@ -724,13 +727,7 @@ static PyObject * faulthandler_sigill(PyObject *self, PyObject *args) { -#if defined(MS_WINDOWS) - /* see faulthandler_sigsegv() for the explanation about while(1) */ - while(1) - raise(SIGILL); -#else raise(SIGILL); -#endif Py_RETURN_NONE; } #endif -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 1 12:14:29 2011 From: python-checkins at python.org (victor.stinner) Date: Fri, 01 Apr 2011 12:14:29 +0200 Subject: [Python-checkins] cpython: Issue #11393: The fault handler handles also SIGABRT Message-ID: http://hg.python.org/cpython/rev/a4fa79b0d478 changeset: 69100:a4fa79b0d478 user: Victor Stinner date: Fri Apr 01 12:13:55 2011 +0200 summary: Issue #11393: The fault handler handles also SIGABRT files: Doc/library/faulthandler.rst | 14 ++++---- Doc/using/cmdline.rst | 5 ++- Lib/test/test_faulthandler.py | 9 ++++++ Modules/faulthandler.c | 33 +++++++++++++++++----- Python/pythonrun.c | 1 + 5 files changed, 45 insertions(+), 17 deletions(-) diff --git a/Doc/library/faulthandler.rst b/Doc/library/faulthandler.rst --- a/Doc/library/faulthandler.rst +++ b/Doc/library/faulthandler.rst @@ -6,10 +6,10 @@ This module contains functions to dump the Python traceback explicitly, on a fault, after a timeout or on a user signal. Call :func:`faulthandler.enable` to -install fault handlers for :const:`SIGSEGV`, :const:`SIGFPE`, :const:`SIGBUS` -and :const:`SIGILL` signals. You can also enable them at startup by setting the -:envvar:`PYTHONFAULTHANDLER` environment variable or by using :option:`-X` -``faulthandler`` command line option. +install fault handlers for :const:`SIGSEGV`, :const:`SIGFPE`, :const:`SIGABRT`, +:const:`SIGBUS` and :const:`SIGILL` signals. You can also enable them at +startup by setting the :envvar:`PYTHONFAULTHANDLER` environment variable or by +using :option:`-X` ``faulthandler`` command line option. The fault handler is compatible with system fault handlers like Apport or the Windows fault handler. The module uses an alternative stack for signal @@ -48,9 +48,9 @@ .. function:: enable(file=sys.stderr, all_threads=False) Enable the fault handler: install handlers for :const:`SIGSEGV`, - :const:`SIGFPE`, :const:`SIGBUS` and :const:`SIGILL` signals to dump the - Python traceback. It dumps the traceback of the current thread, or all - threads if *all_threads* is ``True``, into *file*. + :const:`SIGFPE`, :const:`SIGABRT`, :const:`SIGBUS` and :const:`SIGILL` + signals to dump the Python traceback. It dumps the traceback of the current + thread, or all threads if *all_threads* is ``True``, into *file*. .. function:: disable() diff --git a/Doc/using/cmdline.rst b/Doc/using/cmdline.rst --- a/Doc/using/cmdline.rst +++ b/Doc/using/cmdline.rst @@ -502,8 +502,9 @@ If this environment variable is set, :func:`faulthandler.enable` is called at startup: install a handler for :const:`SIGSEGV`, :const:`SIGFPE`, - :const:`SIGBUS` and :const:`SIGILL` signals to dump the Python traceback. - This is equivalent to :option:`-X` ``faulthandler`` option. + :const:`SIGABRT`, :const:`SIGBUS` and :const:`SIGILL` signals to dump the + Python traceback. This is equivalent to :option:`-X` ``faulthandler`` + option. Debug-mode variables diff --git a/Lib/test/test_faulthandler.py b/Lib/test/test_faulthandler.py --- a/Lib/test/test_faulthandler.py +++ b/Lib/test/test_faulthandler.py @@ -112,6 +112,15 @@ 3, 'Segmentation fault') + def test_sigabrt(self): + self.check_fatal_error(""" +import faulthandler +faulthandler.enable() +faulthandler._sigabrt() +""".strip(), + 3, + 'Aborted') + @unittest.skipIf(sys.platform == 'win32', "SIGFPE cannot be caught on Windows") def test_sigfpe(self): diff --git a/Modules/faulthandler.c b/Modules/faulthandler.c --- a/Modules/faulthandler.c +++ b/Modules/faulthandler.c @@ -10,9 +10,9 @@ #endif #ifndef MS_WINDOWS - /* register() is useless on Windows, because only SIGSEGV and SIGILL can be - handled by the process, and these signals can only be used with enable(), - not using register() */ + /* register() is useless on Windows, because only SIGSEGV, SIGABRT and + SIGILL can be handled by the process, and these signals can only be used + with enable(), not using register() */ # define FAULTHANDLER_USER #endif @@ -96,6 +96,7 @@ {SIGILL, 0, "Illegal instruction", }, #endif {SIGFPE, 0, "Floating point exception", }, + {SIGABRT, 0, "Aborted", }, /* define SIGSEGV at the end to make it the default choice if searching the handler fails in faulthandler_fatal_error() */ {SIGSEGV, 0, "Segmentation fault", } @@ -202,7 +203,7 @@ } -/* Handler of SIGSEGV, SIGFPE, SIGBUS and SIGILL signals. +/* Handler of SIGSEGV, SIGFPE, SIGABRT, SIGBUS and SIGILL signals. Display the current Python traceback, restore the previous handler and call the previous handler. @@ -253,9 +254,9 @@ PUTS(fd, handler->name); PUTS(fd, "\n\n"); - /* SIGSEGV, SIGFPE, SIGBUS and SIGILL are synchronous signals and so are - delivered to the thread that caused the fault. Get the Python thread - state of the current thread. + /* SIGSEGV, SIGFPE, SIGABRT, SIGBUS and SIGILL are synchronous signals and + so are delivered to the thread that caused the fault. Get the Python + thread state of the current thread. PyThreadState_Get() doesn't give the state of the thread that caused the fault if the thread released the GIL, and so this function cannot be @@ -282,7 +283,7 @@ raise(signum); } -/* Install handler for fatal signals (SIGSEGV, SIGFPE, ...). */ +/* Install the handler for fatal signals, faulthandler_fatal_error(). */ static PyObject* faulthandler_enable(PyObject *self, PyObject *args, PyObject *kwargs) @@ -714,6 +715,20 @@ Py_RETURN_NONE; } +static PyObject * +faulthandler_sigabrt(PyObject *self, PyObject *args) +{ +#if _MSC_VER + /* If Python is compiled in debug mode with Visual Studio, abort() opens + a popup asking the user how to handle the assertion. Use raise(SIGABRT) + instead. */ + raise(SIGABRT); +#else + abort(); +#endif + Py_RETURN_NONE; +} + #ifdef SIGBUS static PyObject * faulthandler_sigbus(PyObject *self, PyObject *args) @@ -847,6 +862,8 @@ "a SIGSEGV or SIGBUS signal depending on the platform")}, {"_sigsegv", faulthandler_sigsegv, METH_VARARGS, PyDoc_STR("_sigsegv(): raise a SIGSEGV signal")}, + {"_sigabrt", faulthandler_sigabrt, METH_VARARGS, + PyDoc_STR("_sigabrt(): raise a SIGABRT signal")}, {"_sigfpe", (PyCFunction)faulthandler_sigfpe, METH_NOARGS, PyDoc_STR("_sigfpe(): raise a SIGFPE signal")}, #ifdef SIGBUS diff --git a/Python/pythonrun.c b/Python/pythonrun.c --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -2124,6 +2124,7 @@ fflush(stderr); _Py_DumpTraceback(fd, tstate); } + _PyFaulthandler_Fini(); } #ifdef MS_WINDOWS -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 1 13:10:41 2011 From: python-checkins at python.org (victor.stinner) Date: Fri, 01 Apr 2011 13:10:41 +0200 Subject: [Python-checkins] cpython: Issue #11393: Fix faulthandler.disable() and add a test Message-ID: http://hg.python.org/cpython/rev/a27755b10448 changeset: 69101:a27755b10448 user: Victor Stinner date: Fri Apr 01 12:56:17 2011 +0200 summary: Issue #11393: Fix faulthandler.disable() and add a test files: Lib/test/test_faulthandler.py | 32 +++++++++++++++++----- Modules/faulthandler.c | 8 ++-- 2 files changed, 28 insertions(+), 12 deletions(-) diff --git a/Lib/test/test_faulthandler.py b/Lib/test/test_faulthandler.py --- a/Lib/test/test_faulthandler.py +++ b/Lib/test/test_faulthandler.py @@ -431,13 +431,15 @@ @unittest.skipIf(not hasattr(faulthandler, "register"), "need faulthandler.register") - def check_register(self, filename=False, all_threads=False): + def check_register(self, filename=False, all_threads=False, + unregister=False): """ Register a handler displaying the traceback on a user signal. Raise the signal and check the written traceback. Raise an error if the output doesn't match the expected format. """ + signum = signal.SIGUSR1 code = """ import faulthandler import os @@ -446,12 +448,15 @@ def func(signum): os.kill(os.getpid(), signum) -signum = signal.SIGUSR1 +signum = {signum} +unregister = {unregister} if {has_filename}: file = open({filename}, "wb") else: file = None faulthandler.register(signum, file=file, all_threads={all_threads}) +if unregister: + faulthandler.unregister(signum) func(signum) if file is not None: file.close() @@ -460,20 +465,31 @@ filename=repr(filename), has_filename=bool(filename), all_threads=all_threads, + signum=signum, + unregister=unregister, ) trace, exitcode = self.get_output(code, filename) trace = '\n'.join(trace) - if all_threads: - regex = 'Current thread XXX:\n' + if not unregister: + if all_threads: + regex = 'Current thread XXX:\n' + else: + regex = 'Traceback \(most recent call first\):\n' + regex = expected_traceback(6, 17, regex) + self.assertRegex(trace, regex) else: - regex = 'Traceback \(most recent call first\):\n' - regex = expected_traceback(6, 14, regex) - self.assertRegex(trace, regex) - self.assertEqual(exitcode, 0) + self.assertEqual(trace, '') + if unregister: + self.assertNotEqual(exitcode, 0) + else: + self.assertEqual(exitcode, 0) def test_register(self): self.check_register() + def test_unregister(self): + self.check_register(unregister=True) + def test_register_file(self): with temporary_filename() as filename: self.check_register(filename=filename) diff --git a/Modules/faulthandler.c b/Modules/faulthandler.c --- a/Modules/faulthandler.c +++ b/Modules/faulthandler.c @@ -628,7 +628,7 @@ static int faulthandler_unregister(user_signal_t *user, int signum) { - if (user->enabled) + if (!user->enabled) return 0; user->enabled = 0; #ifdef HAVE_SIGACTION @@ -976,7 +976,7 @@ void _PyFaulthandler_Fini(void) { #ifdef FAULTHANDLER_USER - unsigned int i; + unsigned int signum; #endif #ifdef FAULTHANDLER_LATER @@ -995,8 +995,8 @@ #ifdef FAULTHANDLER_USER /* user */ if (user_signals != NULL) { - for (i=0; i < NSIG; i++) - faulthandler_unregister(&user_signals[i], i+1); + for (signum=0; signum < NSIG; signum++) + faulthandler_unregister(&user_signals[signum], signum); free(user_signals); user_signals = NULL; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 1 15:39:59 2011 From: python-checkins at python.org (victor.stinner) Date: Fri, 01 Apr 2011 15:39:59 +0200 Subject: [Python-checkins] cpython: Issue #11393: _Py_DumpTraceback() writes the header even if there is no frame Message-ID: http://hg.python.org/cpython/rev/7e3ed426962f changeset: 69102:7e3ed426962f user: Victor Stinner date: Fri Apr 01 15:34:01 2011 +0200 summary: Issue #11393: _Py_DumpTraceback() writes the header even if there is no frame files: Include/traceback.h | 4 +--- Python/traceback.c | 14 +++++++------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/Include/traceback.h b/Include/traceback.h --- a/Include/traceback.h +++ b/Include/traceback.h @@ -38,8 +38,6 @@ ... File "xxx", line xxx in - Return 0 on success, -1 on error. - This function is written for debug purpose only, to dump the traceback in the worst case: after a segmentation fault, at fatal error, etc. That's why, it is very limited. Strings are truncated to 100 characters and encoded to @@ -49,7 +47,7 @@ This function is signal safe. */ -PyAPI_DATA(int) _Py_DumpTraceback( +PyAPI_DATA(void) _Py_DumpTraceback( int fd, PyThreadState *tstate); diff --git a/Python/traceback.c b/Python/traceback.c --- a/Python/traceback.c +++ b/Python/traceback.c @@ -556,18 +556,19 @@ write(fd, "\n", 1); } -static int +static void dump_traceback(int fd, PyThreadState *tstate, int write_header) { PyFrameObject *frame; unsigned int depth; + if (write_header) + PUTS(fd, "Traceback (most recent call first):\n"); + frame = _PyThreadState_GetFrame(tstate); if (frame == NULL) - return -1; + return; - if (write_header) - PUTS(fd, "Traceback (most recent call first):\n"); depth = 0; while (frame != NULL) { if (MAX_FRAME_DEPTH <= depth) { @@ -580,13 +581,12 @@ frame = frame->f_back; depth++; } - return 0; } -int +void _Py_DumpTraceback(int fd, PyThreadState *tstate) { - return dump_traceback(fd, tstate, 1); + dump_traceback(fd, tstate, 1); } /* Write the thread identifier into the file 'fd': "Current thread 0xHHHH:\" if -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 1 15:40:03 2011 From: python-checkins at python.org (victor.stinner) Date: Fri, 01 Apr 2011 15:40:03 +0200 Subject: [Python-checkins] cpython: Issue #11393: signal of user signal displays tracebacks even if tstate==NULL Message-ID: http://hg.python.org/cpython/rev/e609105dff64 changeset: 69103:e609105dff64 user: Victor Stinner date: Fri Apr 01 15:37:12 2011 +0200 summary: Issue #11393: signal of user signal displays tracebacks even if tstate==NULL * faulthandler_user() displays the tracebacks of all threads even if it is unable to get the state of the current thread * test_faulthandler: only release the GIL in test_gil_released() check * create check_signum() subfunction files: Lib/test/test_faulthandler.py | 9 ++- Modules/faulthandler.c | 58 ++++++++++++++-------- 2 files changed, 43 insertions(+), 24 deletions(-) diff --git a/Lib/test/test_faulthandler.py b/Lib/test/test_faulthandler.py --- a/Lib/test/test_faulthandler.py +++ b/Lib/test/test_faulthandler.py @@ -8,6 +8,8 @@ import tempfile import unittest +TIMEOUT = 0.5 + try: from resource import setrlimit, RLIMIT_CORE, error as resource_error except ImportError: @@ -189,7 +191,7 @@ import faulthandler output = open({filename}, 'wb') faulthandler.enable(output) -faulthandler._read_null(True) +faulthandler._read_null() """.strip().format(filename=repr(filename)), 4, '(?:Segmentation fault|Bus error)', @@ -199,7 +201,7 @@ self.check_fatal_error(""" import faulthandler faulthandler.enable(all_threads=True) -faulthandler._read_null(True) +faulthandler._read_null() """.strip(), 3, '(?:Segmentation fault|Bus error)', @@ -376,7 +378,7 @@ # Check that sleep() was not interrupted assert (b - a) >= min_pause, "{{}} < {{}}".format(b - a, min_pause) -timeout = 0.5 +timeout = {timeout} repeat = {repeat} cancel = {cancel} if {has_filename}: @@ -394,6 +396,7 @@ has_filename=bool(filename), repeat=repeat, cancel=cancel, + timeout=TIMEOUT, ) trace, exitcode = self.get_output(code, filename) trace = '\n'.join(trace) diff --git a/Modules/faulthandler.c b/Modules/faulthandler.c --- a/Modules/faulthandler.c +++ b/Modules/faulthandler.c @@ -65,6 +65,7 @@ int fd; int all_threads; _Py_sighandler_t previous; + PyInterpreterState *interp; } user_signal_t; static user_signal_t *user_signals; @@ -529,15 +530,35 @@ the thread doesn't hold the GIL. Read the thread local storage (TLS) instead: call PyGILState_GetThisThreadState(). */ tstate = PyGILState_GetThisThreadState(); - if (tstate == NULL) { - /* unable to get the current thread, do nothing */ - return; - } if (user->all_threads) - _Py_DumpTracebackThreads(user->fd, tstate->interp, tstate); - else + _Py_DumpTracebackThreads(user->fd, user->interp, tstate); + else { + if (tstate == NULL) + return; _Py_DumpTraceback(user->fd, tstate); + } +} + +static int +check_signum(int signum) +{ + unsigned int i; + + for (i=0; i < faulthandler_nsignals; i++) { + if (faulthandler_handlers[i].signum == signum) { + PyErr_Format(PyExc_RuntimeError, + "signal %i cannot be registered, " + "use enable() instead", + signum); + return 0; + } + } + if (signum < 1 || NSIG <= signum) { + PyErr_SetString(PyExc_ValueError, "signal number out of range"); + return 0; + } + return 1; } static PyObject* @@ -549,12 +570,12 @@ PyObject *file = NULL; int all_threads = 0; int fd; - unsigned int i; user_signal_t *user; _Py_sighandler_t previous; #ifdef HAVE_SIGACTION struct sigaction action; #endif + PyThreadState *tstate; int err; if (!PyArg_ParseTupleAndKeywords(args, kwargs, @@ -562,19 +583,15 @@ &signum, &file, &all_threads)) return NULL; - if (signum < 1 || NSIG <= signum) { - PyErr_SetString(PyExc_ValueError, "signal number out of range"); + if (!check_signum(signum)) return NULL; - } - for (i=0; i < faulthandler_nsignals; i++) { - if (faulthandler_handlers[i].signum == signum) { - PyErr_Format(PyExc_RuntimeError, - "signal %i cannot be registered by register(), " - "use enable() instead", - signum); - return NULL; - } + /* The caller holds the GIL and so PyThreadState_Get() can be used */ + tstate = PyThreadState_Get(); + if (tstate == NULL) { + PyErr_SetString(PyExc_RuntimeError, + "unable to get the current thread state"); + return NULL; } file = faulthandler_get_fileno(file, &fd); @@ -620,6 +637,7 @@ user->fd = fd; user->all_threads = all_threads; user->previous = previous; + user->interp = tstate->interp; user->enabled = 1; Py_RETURN_NONE; @@ -651,10 +669,8 @@ if (!PyArg_ParseTuple(args, "i:unregister", &signum)) return NULL; - if (signum < 1 || NSIG <= signum) { - PyErr_SetString(PyExc_ValueError, "signal number out of range"); + if (!check_signum(signum)) return NULL; - } user = &user_signals[signum]; change = faulthandler_unregister(user, signum); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 1 16:00:11 2011 From: python-checkins at python.org (victor.stinner) Date: Fri, 01 Apr 2011 16:00:11 +0200 Subject: [Python-checkins] cpython: Issue #11727: set regrtest default timeout to 15 minutes Message-ID: http://hg.python.org/cpython/rev/15f6fe139181 changeset: 69104:15f6fe139181 user: Victor Stinner date: Fri Apr 01 15:59:59 2011 +0200 summary: Issue #11727: set regrtest default timeout to 15 minutes files: Lib/test/regrtest.py | 5 +++-- Misc/NEWS | 4 +++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -22,7 +22,8 @@ -h/--help -- print this text and exit --timeout TIMEOUT -- dump the traceback and exit if a test takes more - than TIMEOUT seconds + than TIMEOUT seconds (default: 15 minutes); disable + the timeout if TIMEOUT is zero Verbosity @@ -239,7 +240,7 @@ findleaks=False, use_resources=None, trace=False, coverdir='coverage', runleaks=False, huntrleaks=False, verbose2=False, print_slow=False, random_seed=None, use_mp=None, verbose3=False, forever=False, - header=False, timeout=None): + header=False, timeout=15*60): """Execute a test suite. This also parses command-line options and modifies its behavior diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -361,7 +361,9 @@ Tests ----- -- Issue #11727: add --timeout option to regrtest (disabled by default). +- Issue #11727: If a test takes more than 15 minutes, regrtest dumps the + traceback of all threads and exits. Use --timeout option to change the + default timeout or to disable it. - Issue #11653: fix -W with -j in regrtest. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 1 18:17:16 2011 From: python-checkins at python.org (r.david.murray) Date: Fri, 01 Apr 2011 18:17:16 +0200 Subject: [Python-checkins] devguide: Top level sections only in sidebar TOC on FAQ page. Message-ID: http://hg.python.org/devguide/rev/1dc036ca6c94 changeset: 409:1dc036ca6c94 user: R David Murray date: Fri Apr 01 12:16:53 2011 -0400 summary: Top level sections only in sidebar TOC on FAQ page. files: faq.rst | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/faq.rst b/faq.rst --- a/faq.rst +++ b/faq.rst @@ -1,3 +1,5 @@ +:tocdepth: 2 + .. _faq: Python Developer FAQ -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Fri Apr 1 18:40:20 2011 From: python-checkins at python.org (victor.stinner) Date: Fri, 01 Apr 2011 18:40:20 +0200 Subject: [Python-checkins] cpython: Issue #11727: set regrtest default timeout to 30 minutes Message-ID: http://hg.python.org/cpython/rev/053bc5ca199b changeset: 69105:053bc5ca199b user: Victor Stinner date: Fri Apr 01 18:16:36 2011 +0200 summary: Issue #11727: set regrtest default timeout to 30 minutes files: Lib/test/regrtest.py | 4 ++-- Misc/NEWS | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -22,7 +22,7 @@ -h/--help -- print this text and exit --timeout TIMEOUT -- dump the traceback and exit if a test takes more - than TIMEOUT seconds (default: 15 minutes); disable + than TIMEOUT seconds (default: 30 minutes); disable the timeout if TIMEOUT is zero Verbosity @@ -240,7 +240,7 @@ findleaks=False, use_resources=None, trace=False, coverdir='coverage', runleaks=False, huntrleaks=False, verbose2=False, print_slow=False, random_seed=None, use_mp=None, verbose3=False, forever=False, - header=False, timeout=15*60): + header=False, timeout=30*60): """Execute a test suite. This also parses command-line options and modifies its behavior diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -361,7 +361,7 @@ Tests ----- -- Issue #11727: If a test takes more than 15 minutes, regrtest dumps the +- Issue #11727: If a test takes more than 30 minutes, regrtest dumps the traceback of all threads and exits. Use --timeout option to change the default timeout or to disable it. -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Sat Apr 2 04:57:59 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sat, 02 Apr 2011 04:57:59 +0200 Subject: [Python-checkins] Daily reference leaks (053bc5ca199b): sum=0 Message-ID: results for 053bc5ca199b on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflog21pzX3', '-x'] From solipsis at pitrou.net Sun Apr 3 04:55:31 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sun, 03 Apr 2011 04:55:31 +0200 Subject: [Python-checkins] Daily reference leaks (053bc5ca199b): sum=-56 Message-ID: results for 053bc5ca199b on branch "default" -------------------------------------------- test_pyexpat leaked [0, 0, -56] references, sum=-56 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogPtWxL8', '-x'] From python-checkins at python.org Sun Apr 3 15:26:49 2011 From: python-checkins at python.org (ezio.melotti) Date: Sun, 03 Apr 2011 15:26:49 +0200 Subject: [Python-checkins] cpython (3.1): Fix typo noticed by Sandro Tosi. Message-ID: http://hg.python.org/cpython/rev/821244a44163 changeset: 69106:821244a44163 branch: 3.1 parent: 69066:8e074d9b1587 user: Ezio Melotti date: Sun Apr 03 16:20:21 2011 +0300 summary: Fix typo noticed by Sandro Tosi. files: Doc/library/profile.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/profile.rst b/Doc/library/profile.rst --- a/Doc/library/profile.rst +++ b/Doc/library/profile.rst @@ -48,7 +48,7 @@ The profiler modules are designed to provide an execution profile for a given program, not for benchmarking purposes (for that, there is :mod:`timeit` for - resonably accurate results). This particularly applies to benchmarking + reasonably accurate results). This particularly applies to benchmarking Python code against C code: the profilers introduce overhead for Python code, but not for C-level functions, and so the C code would seem faster than any Python one. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Apr 3 15:26:49 2011 From: python-checkins at python.org (ezio.melotti) Date: Sun, 03 Apr 2011 15:26:49 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): Merge with 3.1 Message-ID: http://hg.python.org/cpython/rev/5fd1ac1c9474 changeset: 69107:5fd1ac1c9474 branch: 3.2 parent: 69093:7aa3f1f7ac94 parent: 69106:821244a44163 user: Ezio Melotti date: Sun Apr 03 16:24:22 2011 +0300 summary: Merge with 3.1 files: Doc/library/profile.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/profile.rst b/Doc/library/profile.rst --- a/Doc/library/profile.rst +++ b/Doc/library/profile.rst @@ -50,7 +50,7 @@ The profiler modules are designed to provide an execution profile for a given program, not for benchmarking purposes (for that, there is :mod:`timeit` for - resonably accurate results). This particularly applies to benchmarking + reasonably accurate results). This particularly applies to benchmarking Python code against C code: the profilers introduce overhead for Python code, but not for C-level functions, and so the C code would seem faster than any Python one. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Apr 3 15:26:50 2011 From: python-checkins at python.org (ezio.melotti) Date: Sun, 03 Apr 2011 15:26:50 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge with 3.2 Message-ID: http://hg.python.org/cpython/rev/ca5932a51a9b changeset: 69108:ca5932a51a9b parent: 69105:053bc5ca199b parent: 69107:5fd1ac1c9474 user: Ezio Melotti date: Sun Apr 03 16:25:49 2011 +0300 summary: Merge with 3.2 files: Doc/library/profile.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/profile.rst b/Doc/library/profile.rst --- a/Doc/library/profile.rst +++ b/Doc/library/profile.rst @@ -50,7 +50,7 @@ The profiler modules are designed to provide an execution profile for a given program, not for benchmarking purposes (for that, there is :mod:`timeit` for - resonably accurate results). This particularly applies to benchmarking + reasonably accurate results). This particularly applies to benchmarking Python code against C code: the profilers introduce overhead for Python code, but not for C-level functions, and so the C code would seem faster than any Python one. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Apr 3 17:03:32 2011 From: python-checkins at python.org (ezio.melotti) Date: Sun, 03 Apr 2011 17:03:32 +0200 Subject: [Python-checkins] cpython (3.2): #11282: the fail* methods will stay around a few more versions. Message-ID: http://hg.python.org/cpython/rev/1fd736395df3 changeset: 69109:1fd736395df3 branch: 3.2 parent: 69107:5fd1ac1c9474 user: Ezio Melotti date: Sun Apr 03 17:37:58 2011 +0300 summary: #11282: the fail* methods will stay around a few more versions. files: Doc/library/unittest.rst | 2 +- Lib/unittest/case.py | 3 +-- Lib/unittest/test/test_case.py | 6 ++---- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/Doc/library/unittest.rst b/Doc/library/unittest.rst --- a/Doc/library/unittest.rst +++ b/Doc/library/unittest.rst @@ -1459,7 +1459,7 @@ :meth:`.assertRaisesRegex` assertRaisesRegexp ============================== ====================== ====================== - .. deprecated-removed:: 3.1 3.3 + .. deprecated:: 3.1 the fail* aliases listed in the second column. .. deprecated:: 3.2 the assert* aliases listed in the third column. diff --git a/Lib/unittest/case.py b/Lib/unittest/case.py --- a/Lib/unittest/case.py +++ b/Lib/unittest/case.py @@ -1181,8 +1181,7 @@ return original_func(*args, **kwargs) return deprecated_func - # The fail* methods can be removed in 3.3, the 5 assert* methods will - # have to stay around for a few more versions. See #9424. + # see #9424 failUnlessEqual = assertEquals = _deprecate(assertEqual) failIfEqual = assertNotEquals = _deprecate(assertNotEqual) failUnlessAlmostEqual = assertAlmostEquals = _deprecate(assertAlmostEqual) diff --git a/Lib/unittest/test/test_case.py b/Lib/unittest/test/test_case.py --- a/Lib/unittest/test/test_case.py +++ b/Lib/unittest/test/test_case.py @@ -1088,10 +1088,8 @@ _runtime_warn("barz") def testDeprecatedMethodNames(self): - """Test that the deprecated methods raise a DeprecationWarning. - - The fail* methods will be removed in 3.3. The assert* methods will - have to stay around for a few more versions. See #9424. + """ + Test that the deprecated methods raise a DeprecationWarning. See #9424. """ old = ( (self.failIfEqual, (3, 5)), -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Apr 3 17:03:33 2011 From: python-checkins at python.org (ezio.melotti) Date: Sun, 03 Apr 2011 17:03:33 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): #11282: merge with 3.2. Message-ID: http://hg.python.org/cpython/rev/110bb604bc2f changeset: 69110:110bb604bc2f parent: 69108:ca5932a51a9b parent: 69109:1fd736395df3 user: Ezio Melotti date: Sun Apr 03 17:39:19 2011 +0300 summary: #11282: merge with 3.2. files: Doc/library/unittest.rst | 2 +- Lib/unittest/case.py | 3 +-- Lib/unittest/test/test_case.py | 6 ++---- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/Doc/library/unittest.rst b/Doc/library/unittest.rst --- a/Doc/library/unittest.rst +++ b/Doc/library/unittest.rst @@ -1462,7 +1462,7 @@ :meth:`.assertRaisesRegex` assertRaisesRegexp ============================== ====================== ====================== - .. deprecated-removed:: 3.1 3.3 + .. deprecated:: 3.1 the fail* aliases listed in the second column. .. deprecated:: 3.2 the assert* aliases listed in the third column. diff --git a/Lib/unittest/case.py b/Lib/unittest/case.py --- a/Lib/unittest/case.py +++ b/Lib/unittest/case.py @@ -1110,8 +1110,7 @@ return original_func(*args, **kwargs) return deprecated_func - # The fail* methods can be removed in 3.3, the 5 assert* methods will - # have to stay around for a few more versions. See #9424. + # see #9424 assertEquals = _deprecate(assertEqual) assertNotEquals = _deprecate(assertNotEqual) assertAlmostEquals = _deprecate(assertAlmostEqual) diff --git a/Lib/unittest/test/test_case.py b/Lib/unittest/test/test_case.py --- a/Lib/unittest/test/test_case.py +++ b/Lib/unittest/test/test_case.py @@ -1093,10 +1093,8 @@ _runtime_warn("barz") def testDeprecatedMethodNames(self): - """Test that the deprecated methods raise a DeprecationWarning. - - The fail* methods will be removed in 3.3. The assert* methods will - have to stay around for a few more versions. See #9424. + """ + Test that the deprecated methods raise a DeprecationWarning. See #9424. """ old = ( (self.assertNotEquals, (3, 5)), -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Apr 3 17:03:36 2011 From: python-checkins at python.org (ezio.melotti) Date: Sun, 03 Apr 2011 17:03:36 +0200 Subject: [Python-checkins] cpython: #11282: add back the fail* methods and assertDictContainsSubset. Message-ID: http://hg.python.org/cpython/rev/aa658836e090 changeset: 69111:aa658836e090 user: Ezio Melotti date: Sun Apr 03 18:02:13 2011 +0300 summary: #11282: add back the fail* methods and assertDictContainsSubset. files: Lib/unittest/case.py | 41 ++++++++++- Lib/unittest/test/_test_warnings.py | 7 +- Lib/unittest/test/test_assertions.py | 9 ++ Lib/unittest/test/test_case.py | 53 ++++++++++++++++ Lib/unittest/test/test_runner.py | 10 ++- Misc/NEWS | 2 + 6 files changed, 113 insertions(+), 9 deletions(-) diff --git a/Lib/unittest/case.py b/Lib/unittest/case.py --- a/Lib/unittest/case.py +++ b/Lib/unittest/case.py @@ -938,6 +938,35 @@ standardMsg = self._truncateMessage(standardMsg, diff) self.fail(self._formatMessage(msg, standardMsg)) + def assertDictContainsSubset(self, subset, dictionary, msg=None): + """Checks whether dictionary is a superset of subset.""" + warnings.warn('assertDictContainsSubset is deprecated', + DeprecationWarning) + missing = [] + mismatched = [] + for key, value in subset.items(): + if key not in dictionary: + missing.append(key) + elif value != dictionary[key]: + mismatched.append('%s, expected: %s, actual: %s' % + (safe_repr(key), safe_repr(value), + safe_repr(dictionary[key]))) + + if not (missing or mismatched): + return + + standardMsg = '' + if missing: + standardMsg = 'Missing: %s' % ','.join(safe_repr(m) for m in + missing) + if mismatched: + if standardMsg: + standardMsg += '; ' + standardMsg += 'Mismatched values: %s' % ','.join(mismatched) + + self.fail(self._formatMessage(msg, standardMsg)) + + def assertCountEqual(self, first, second, msg=None): """An unordered sequence comparison asserting that the same elements, regardless of order. If the same element occurs more than once, @@ -1111,11 +1140,13 @@ return deprecated_func # see #9424 - assertEquals = _deprecate(assertEqual) - assertNotEquals = _deprecate(assertNotEqual) - assertAlmostEquals = _deprecate(assertAlmostEqual) - assertNotAlmostEquals = _deprecate(assertNotAlmostEqual) - assert_ = _deprecate(assertTrue) + failUnlessEqual = assertEquals = _deprecate(assertEqual) + failIfEqual = assertNotEquals = _deprecate(assertNotEqual) + failUnlessAlmostEqual = assertAlmostEquals = _deprecate(assertAlmostEqual) + failIfAlmostEqual = assertNotAlmostEquals = _deprecate(assertNotAlmostEqual) + failUnless = assert_ = _deprecate(assertTrue) + failUnlessRaises = _deprecate(assertRaises) + failIf = _deprecate(assertFalse) assertRaisesRegexp = _deprecate(assertRaisesRegex) assertRegexpMatches = _deprecate(assertRegex) diff --git a/Lib/unittest/test/_test_warnings.py b/Lib/unittest/test/_test_warnings.py --- a/Lib/unittest/test/_test_warnings.py +++ b/Lib/unittest/test/_test_warnings.py @@ -19,12 +19,17 @@ warnings.warn('rw', RuntimeWarning) class TestWarnings(unittest.TestCase): - # unittest warnings will be printed at most once per type + # unittest warnings will be printed at most once per type (max one message + # for the fail* methods, and one for the assert* methods) def test_assert(self): self.assertEquals(2+2, 4) self.assertEquals(2*2, 4) self.assertEquals(2**2, 4) + def test_fail(self): + self.failUnless(1) + self.failUnless(True) + def test_other_unittest(self): self.assertAlmostEqual(2+2, 4) self.assertNotAlmostEqual(4+4, 2) diff --git a/Lib/unittest/test/test_assertions.py b/Lib/unittest/test/test_assertions.py --- a/Lib/unittest/test/test_assertions.py +++ b/Lib/unittest/test/test_assertions.py @@ -223,6 +223,15 @@ "\+ \{'key': 'value'\}$", "\+ \{'key': 'value'\} : oops$"]) + def testAssertDictContainsSubset(self): + with warnings.catch_warnings(): + warnings.simplefilter("ignore", DeprecationWarning) + + self.assertMessages('assertDictContainsSubset', ({'key': 'value'}, {}), + ["^Missing: 'key'$", "^oops$", + "^Missing: 'key'$", + "^Missing: 'key' : oops$"]) + def testAssertMultiLineEqual(self): self.assertMessages('assertMultiLineEqual', ("", "foo"), [r"\+ foo$", "^oops$", diff --git a/Lib/unittest/test/test_case.py b/Lib/unittest/test/test_case.py --- a/Lib/unittest/test/test_case.py +++ b/Lib/unittest/test/test_case.py @@ -523,6 +523,36 @@ self.assertRaises(self.failureException, self.assertNotIn, 'cow', animals) + def testAssertDictContainsSubset(self): + with warnings.catch_warnings(): + warnings.simplefilter("ignore", DeprecationWarning) + + self.assertDictContainsSubset({}, {}) + self.assertDictContainsSubset({}, {'a': 1}) + self.assertDictContainsSubset({'a': 1}, {'a': 1}) + self.assertDictContainsSubset({'a': 1}, {'a': 1, 'b': 2}) + self.assertDictContainsSubset({'a': 1, 'b': 2}, {'a': 1, 'b': 2}) + + with self.assertRaises(self.failureException): + self.assertDictContainsSubset({1: "one"}, {}) + + with self.assertRaises(self.failureException): + self.assertDictContainsSubset({'a': 2}, {'a': 1}) + + with self.assertRaises(self.failureException): + self.assertDictContainsSubset({'c': 1}, {'a': 1}) + + with self.assertRaises(self.failureException): + self.assertDictContainsSubset({'a': 1, 'c': 1}, {'a': 1}) + + with self.assertRaises(self.failureException): + self.assertDictContainsSubset({'a': 1, 'c': 1}, {'a': 1}) + + one = ''.join(chr(i) for i in range(255)) + # this used to cause a UnicodeDecodeError constructing the failure msg + with self.assertRaises(self.failureException): + self.assertDictContainsSubset({'foo': one}, {'foo': '\uFFFD'}) + def testAssertEqual(self): equal_pairs = [ ((), ()), @@ -1097,11 +1127,19 @@ Test that the deprecated methods raise a DeprecationWarning. See #9424. """ old = ( + (self.failIfEqual, (3, 5)), (self.assertNotEquals, (3, 5)), + (self.failUnlessEqual, (3, 3)), (self.assertEquals, (3, 3)), + (self.failUnlessAlmostEqual, (2.0, 2.0)), (self.assertAlmostEquals, (2.0, 2.0)), + (self.failIfAlmostEqual, (3.0, 5.0)), (self.assertNotAlmostEquals, (3.0, 5.0)), + (self.failUnless, (True,)), (self.assert_, (True,)), + (self.failUnlessRaises, (TypeError, lambda _: 3.14 + 'spam')), + (self.failIf, (False,)), + (self.assertDictContainsSubset, (dict(a=1, b=2), dict(a=1, b=2, c=3))), (self.assertRaisesRegexp, (KeyError, 'foo', lambda: {}['foo'])), (self.assertRegexpMatches, ('bar', 'bar')), ) @@ -1109,6 +1147,21 @@ with self.assertWarns(DeprecationWarning): meth(*args) + # disable this test for now. When the version where the fail* methods will + # be removed is decided, re-enable it and update the version + def _testDeprecatedFailMethods(self): + """Test that the deprecated fail* methods get removed in 3.x""" + if sys.version_info[:2] < (3, 3): + return + deprecated_names = [ + 'failIfEqual', 'failUnlessEqual', 'failUnlessAlmostEqual', + 'failIfAlmostEqual', 'failUnless', 'failUnlessRaises', 'failIf', + 'assertDictContainsSubset', + ] + for deprecated_name in deprecated_names: + with self.assertRaises(AttributeError): + getattr(self, deprecated_name) # remove these in 3.x + def testDeepcopy(self): # Issue: 5660 class TestableTest(unittest.TestCase): diff --git a/Lib/unittest/test/test_runner.py b/Lib/unittest/test/test_runner.py --- a/Lib/unittest/test/test_runner.py +++ b/Lib/unittest/test/test_runner.py @@ -257,17 +257,19 @@ return [b.splitlines() for b in p.communicate()] opts = dict(stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=os.path.dirname(__file__)) + ae_msg = b'Please use assertEqual instead.' + at_msg = b'Please use assertTrue instead.' # no args -> all the warnings are printed, unittest warnings only once p = subprocess.Popen([sys.executable, '_test_warnings.py'], **opts) out, err = get_parse_out_err(p) self.assertIn(b'OK', err) # check that the total number of warnings in the output is correct - self.assertEqual(len(out), 11) + self.assertEqual(len(out), 12) # check that the numbers of the different kind of warnings is correct for msg in [b'dw', b'iw', b'uw']: self.assertEqual(out.count(msg), 3) - for msg in [b'rw']: + for msg in [ae_msg, at_msg, b'rw']: self.assertEqual(out.count(msg), 1) args_list = ( @@ -292,9 +294,11 @@ **opts) out, err = get_parse_out_err(p) self.assertIn(b'OK', err) - self.assertEqual(len(out), 13) + self.assertEqual(len(out), 14) for msg in [b'dw', b'iw', b'uw', b'rw']: self.assertEqual(out.count(msg), 3) + for msg in [ae_msg, at_msg]: + self.assertEqual(out.count(msg), 1) def testStdErrLookedUpAtInstantiationTime(self): # see issue 10786 diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -87,6 +87,8 @@ Library ------- +- unittest.TestCase.assertSameElements has been removed. + - sys.getfilesystemencoding() raises a RuntimeError if initfsencoding() was not called yet: detect bootstrap (startup) issues earlier. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Apr 3 17:09:10 2011 From: python-checkins at python.org (antoine.pitrou) Date: Sun, 03 Apr 2011 17:09:10 +0200 Subject: [Python-checkins] cpython: Issue #5863: Rewrite BZ2File in pure Python, and allow it to accept Message-ID: http://hg.python.org/cpython/rev/2cb07a46f4b5 changeset: 69112:2cb07a46f4b5 user: Antoine Pitrou date: Sun Apr 03 17:05:46 2011 +0200 summary: Issue #5863: Rewrite BZ2File in pure Python, and allow it to accept file-like objects using a new `fileobj` constructor argument. Patch by Nadeem Vawda. files: Doc/ACKS.txt | 1 + Doc/library/bz2.rst | 221 +- Lib/bz2.py | 392 +++++ Lib/test/test_bz2.py | 142 +- Misc/NEWS | 4 + Modules/bz2module.c | 2281 ++++------------------------- PCbuild/bz2.vcproj | 4 +- PCbuild/pcbuild.sln | 2 +- PCbuild/readme.txt | 6 +- setup.py | 4 +- 10 files changed, 960 insertions(+), 2097 deletions(-) diff --git a/Doc/ACKS.txt b/Doc/ACKS.txt --- a/Doc/ACKS.txt +++ b/Doc/ACKS.txt @@ -202,6 +202,7 @@ * Jim Tittsler * David Turner * Ville Vainio + * Nadeem Vawda * Martijn Vries * Charles G. Waldman * Greg Ward diff --git a/Doc/library/bz2.rst b/Doc/library/bz2.rst --- a/Doc/library/bz2.rst +++ b/Doc/library/bz2.rst @@ -1,189 +1,149 @@ -:mod:`bz2` --- Compression compatible with :program:`bzip2` -=========================================================== +:mod:`bz2` --- Support for :program:`bzip2` compression +======================================================= .. module:: bz2 - :synopsis: Interface to compression and decompression routines - compatible with bzip2. + :synopsis: Interfaces for bzip2 compression and decompression. .. moduleauthor:: Gustavo Niemeyer +.. moduleauthor:: Nadeem Vawda .. sectionauthor:: Gustavo Niemeyer +.. sectionauthor:: Nadeem Vawda -This module provides a comprehensive interface for the bz2 compression library. -It implements a complete file interface, one-shot (de)compression functions, and -types for sequential (de)compression. +This module provides a comprehensive interface for compressing and +decompressing data using the bzip2 compression algorithm. -For other archive formats, see the :mod:`gzip`, :mod:`zipfile`, and +For related file formats, see the :mod:`gzip`, :mod:`zipfile`, and :mod:`tarfile` modules. -Here is a summary of the features offered by the bz2 module: +The :mod:`bz2` module contains: -* :class:`BZ2File` class implements a complete file interface, including - :meth:`~BZ2File.readline`, :meth:`~BZ2File.readlines`, - :meth:`~BZ2File.writelines`, :meth:`~BZ2File.seek`, etc; +* The :class:`BZ2File` class for reading and writing compressed files. +* The :class:`BZ2Compressor` and :class:`BZ2Decompressor` classes for + incremental (de)compression. +* The :func:`compress` and :func:`decompress` functions for one-shot + (de)compression. -* :class:`BZ2File` class implements emulated :meth:`~BZ2File.seek` support; - -* :class:`BZ2File` class implements universal newline support; - -* :class:`BZ2File` class offers an optimized line iteration using a readahead - algorithm; - -* Sequential (de)compression supported by :class:`BZ2Compressor` and - :class:`BZ2Decompressor` classes; - -* One-shot (de)compression supported by :func:`compress` and :func:`decompress` - functions; - -* Thread safety uses individual locking mechanism. +All of the classes in this module may safely be accessed from multiple threads. (De)compression of files ------------------------ -Handling of compressed files is offered by the :class:`BZ2File` class. +.. class:: BZ2File(filename=None, mode='r', buffering=None, compresslevel=9, fileobj=None) + Open a bzip2-compressed file. -.. class:: BZ2File(filename, mode='r', buffering=0, compresslevel=9) + The :class:`BZ2File` can wrap an existing :term:`file object` (given by + *fileobj*), or operate directly on a named file (named by *filename*). + Exactly one of these two parameters should be provided. - Open a bz2 file. Mode can be either ``'r'`` or ``'w'``, for reading (default) - or writing. When opened for writing, the file will be created if it doesn't - exist, and truncated otherwise. If *buffering* is given, ``0`` means - unbuffered, and larger numbers specify the buffer size; the default is - ``0``. If *compresslevel* is given, it must be a number between ``1`` and - ``9``; the default is ``9``. Add a ``'U'`` to mode to open the file for input - with universal newline support. Any line ending in the input file will be - seen as a ``'\n'`` in Python. Also, a file so opened gains the attribute - :attr:`newlines`; the value for this attribute is one of ``None`` (no newline - read yet), ``'\r'``, ``'\n'``, ``'\r\n'`` or a tuple containing all the - newline types seen. Universal newlines are available only when - reading. Instances support iteration in the same way as normal :class:`file` - instances. + The *mode* argument can be either ``'r'`` for reading (default), or ``'w'`` + for writing. - :class:`BZ2File` supports the :keyword:`with` statement. + The *buffering* argument is ignored. Its use is deprecated. + + If *mode* is ``'w'``, *compresslevel* can be a number between ``1`` and + ``9`` specifying the level of compression: ``1`` produces the least + compression, and ``9`` (default) produces the most compression. + + :class:`BZ2File` provides all of the members specified by the + :class:`io.BufferedIOBase`, except for :meth:`detach` and :meth:`truncate`. + Iteration and the :keyword:`with` statement are supported. + + :class:`BZ2File` also provides the following method: + + .. method:: peek([n]) + + Return buffered data without advancing the file position. At least one + byte of data will be returned (unless at EOF). The exact number of bytes + returned is unspecified. + + .. versionadded:: 3.3 .. versionchanged:: 3.1 Support for the :keyword:`with` statement was added. + .. versionchanged:: 3.3 + The :meth:`fileno`, :meth:`readable`, :meth:`seekable`, :meth:`writable`, + :meth:`read1` and :meth:`readinto` methods were added. - .. method:: close() + .. versionchanged:: 3.3 + The *fileobj* argument to the constructor was added. - Close the file. Sets data attribute :attr:`closed` to true. A closed file - cannot be used for further I/O operations. :meth:`close` may be called - more than once without error. - - .. method:: read([size]) - - Read at most *size* uncompressed bytes, returned as a byte string. If the - *size* argument is negative or omitted, read until EOF is reached. - - - .. method:: readline([size]) - - Return the next line from the file, as a byte string, retaining newline. - A non-negative *size* argument limits the maximum number of bytes to - return (an incomplete line may be returned then). Return an empty byte - string at EOF. - - - .. method:: readlines([size]) - - Return a list of lines read. The optional *size* argument, if given, is an - approximate bound on the total number of bytes in the lines returned. - - - .. method:: seek(offset[, whence]) - - Move to new file position. Argument *offset* is a byte count. Optional - argument *whence* defaults to ``os.SEEK_SET`` or ``0`` (offset from start - of file; offset should be ``>= 0``); other values are ``os.SEEK_CUR`` or - ``1`` (move relative to current position; offset can be positive or - negative), and ``os.SEEK_END`` or ``2`` (move relative to end of file; - offset is usually negative, although many platforms allow seeking beyond - the end of a file). - - Note that seeking of bz2 files is emulated, and depending on the - parameters the operation may be extremely slow. - - - .. method:: tell() - - Return the current file position, an integer. - - - .. method:: write(data) - - Write the byte string *data* to file. Note that due to buffering, - :meth:`close` may be needed before the file on disk reflects the data - written. - - - .. method:: writelines(sequence_of_byte_strings) - - Write the sequence of byte strings to the file. Note that newlines are not - added. The sequence can be any iterable object producing byte strings. - This is equivalent to calling write() for each byte string. - - -Sequential (de)compression --------------------------- - -Sequential compression and decompression is done using the classes -:class:`BZ2Compressor` and :class:`BZ2Decompressor`. - +Incremental (de)compression +--------------------------- .. class:: BZ2Compressor(compresslevel=9) Create a new compressor object. This object may be used to compress data - sequentially. If you want to compress data in one shot, use the - :func:`compress` function instead. The *compresslevel* parameter, if given, - must be a number between ``1`` and ``9``; the default is ``9``. + incrementally. For one-shot compression, use the :func:`compress` function + instead. + + *compresslevel*, if given, must be a number between ``1`` and ``9``. The + default is ``9``. .. method:: compress(data) - Provide more data to the compressor object. It will return chunks of - compressed data whenever possible. When you've finished providing data to - compress, call the :meth:`flush` method to finish the compression process, - and return what is left in internal buffers. + Provide data to the compressor object. Returns a chunk of compressed data + if possible, or an empty byte string otherwise. + + When you have finished providing data to the compressor, call the + :meth:`flush` method to finish the compression process. .. method:: flush() - Finish the compression process and return what is left in internal - buffers. You must not use the compressor object after calling this method. + Finish the compression process. Returns the compressed data left in + internal buffers. + + The compressor object may not be used after this method has been called. .. class:: BZ2Decompressor() Create a new decompressor object. This object may be used to decompress data - sequentially. If you want to decompress data in one shot, use the - :func:`decompress` function instead. + incrementally. For one-shot compression, use the :func:`decompress` function + instead. .. method:: decompress(data) - Provide more data to the decompressor object. It will return chunks of - decompressed data whenever possible. If you try to decompress data after - the end of stream is found, :exc:`EOFError` will be raised. If any data - was found after the end of stream, it'll be ignored and saved in - :attr:`unused_data` attribute. + Provide data to the decompressor object. Returns a chunk of decompressed + data if possible, or an empty byte string otherwise. + + Attempting to decompress data after the end of stream is reached raises + an :exc:`EOFError`. If any data is found after the end of the stream, it + is ignored and saved in the :attr:`unused_data` attribute. + + + .. attribute:: eof + + True if the end-of-stream marker has been reached. + + .. versionadded:: 3.3 + + + .. attribute:: unused_data + + Data found after the end of the compressed stream. One-shot (de)compression ------------------------ -One-shot compression and decompression is provided through the :func:`compress` -and :func:`decompress` functions. - - .. function:: compress(data, compresslevel=9) - Compress *data* in one shot. If you want to compress data sequentially, use - an instance of :class:`BZ2Compressor` instead. The *compresslevel* parameter, - if given, must be a number between ``1`` and ``9``; the default is ``9``. + Compress *data*. + + *compresslevel*, if given, must be a number between ``1`` and ``9``. The + default is ``9``. + + For incremental compression, use a :class:`BZ2Compressor` instead. .. function:: decompress(data) - Decompress *data* in one shot. If you want to decompress data sequentially, - use an instance of :class:`BZ2Decompressor` instead. + Decompress *data*. + For incremental decompression, use a :class:`BZ2Decompressor` instead. + diff --git a/Lib/bz2.py b/Lib/bz2.py new file mode 100644 --- /dev/null +++ b/Lib/bz2.py @@ -0,0 +1,392 @@ +"""Interface to the libbzip2 compression library. + +This module provides a file interface, classes for incremental +(de)compression, and functions for one-shot (de)compression. +""" + +__all__ = ["BZ2File", "BZ2Compressor", "BZ2Decompressor", "compress", + "decompress"] + +__author__ = "Nadeem Vawda " + +import io +import threading +import warnings + +from _bz2 import BZ2Compressor, BZ2Decompressor + + +_MODE_CLOSED = 0 +_MODE_READ = 1 +_MODE_READ_EOF = 2 +_MODE_WRITE = 3 + +_BUFFER_SIZE = 8192 + + +class BZ2File(io.BufferedIOBase): + + """A file object providing transparent bzip2 (de)compression. + + A BZ2File can act as a wrapper for an existing file object, or refer + directly to a named file on disk. + + Note that BZ2File provides a *binary* file interface - data read is + returned as bytes, and data to be written should be given as bytes. + """ + + def __init__(self, filename=None, mode="r", buffering=None, + compresslevel=9, fileobj=None): + """Open a bzip2-compressed file. + + If filename is given, open the named file. Otherwise, operate on + the file object given by fileobj. Exactly one of these two + parameters should be provided. + + mode can be 'r' for reading (default), or 'w' for writing. + + buffering is ignored. Its use is deprecated. + + If mode is 'w', compresslevel can be a number between 1 and 9 + specifying the level of compression: 1 produces the least + compression, and 9 (default) produces the most compression. + """ + # This lock must be recursive, so that BufferedIOBase's + # readline(), readlines() and writelines() don't deadlock. + self._lock = threading.RLock() + self._fp = None + self._closefp = False + self._mode = _MODE_CLOSED + self._pos = 0 + self._size = -1 + + if buffering is not None: + warnings.warn("Use of 'buffering' argument is deprecated", + DeprecationWarning) + + if not (1 <= compresslevel <= 9): + raise ValueError("compresslevel must be between 1 and 9") + + if mode in ("", "r", "rb"): + mode = "rb" + mode_code = _MODE_READ + self._decompressor = BZ2Decompressor() + self._buffer = None + elif mode in ("w", "wb"): + mode = "wb" + mode_code = _MODE_WRITE + self._compressor = BZ2Compressor() + else: + raise ValueError("Invalid mode: {!r}".format(mode)) + + if filename is not None and fileobj is None: + self._fp = open(filename, mode) + self._closefp = True + self._mode = mode_code + elif fileobj is not None and filename is None: + self._fp = fileobj + self._mode = mode_code + else: + raise ValueError("Must give exactly one of filename and fileobj") + + def close(self): + """Flush and close the file. + + May be called more than once without error. Once the file is + closed, any other operation on it will raise a ValueError. + """ + with self._lock: + if self._mode == _MODE_CLOSED: + return + try: + if self._mode in (_MODE_READ, _MODE_READ_EOF): + self._decompressor = None + elif self._mode == _MODE_WRITE: + self._fp.write(self._compressor.flush()) + self._compressor = None + finally: + try: + if self._closefp: + self._fp.close() + finally: + self._fp = None + self._closefp = False + self._mode = _MODE_CLOSED + self._buffer = None + + @property + def closed(self): + """True if this file is closed.""" + return self._mode == _MODE_CLOSED + + def fileno(self): + """Return the file descriptor for the underlying file.""" + return self._fp.fileno() + + def seekable(self): + """Return whether the file supports seeking.""" + return self.readable() + + def readable(self): + """Return whether the file was opened for reading.""" + return self._mode in (_MODE_READ, _MODE_READ_EOF) + + def writable(self): + """Return whether the file was opened for writing.""" + return self._mode == _MODE_WRITE + + # Mode-checking helper functions. + + def _check_not_closed(self): + if self.closed: + raise ValueError("I/O operation on closed file") + + def _check_can_read(self): + if not self.readable(): + self._check_not_closed() + raise io.UnsupportedOperation("File not open for reading") + + def _check_can_write(self): + if not self.writable(): + self._check_not_closed() + raise io.UnsupportedOperation("File not open for writing") + + def _check_can_seek(self): + if not self.seekable(): + self._check_not_closed() + raise io.UnsupportedOperation("Seeking is only supported " + "on files opening for reading") + + # Fill the readahead buffer if it is empty. Returns False on EOF. + def _fill_buffer(self): + if self._buffer: + return True + if self._decompressor.eof: + self._mode = _MODE_READ_EOF + self._size = self._pos + return False + rawblock = self._fp.read(_BUFFER_SIZE) + if not rawblock: + raise EOFError("Compressed file ended before the " + "end-of-stream marker was reached") + self._buffer = self._decompressor.decompress(rawblock) + return True + + # Read data until EOF. + # If return_data is false, consume the data without returning it. + def _read_all(self, return_data=True): + blocks = [] + while self._fill_buffer(): + if return_data: + blocks.append(self._buffer) + self._pos += len(self._buffer) + self._buffer = None + if return_data: + return b"".join(blocks) + + # Read a block of up to n bytes. + # If return_data is false, consume the data without returning it. + def _read_block(self, n, return_data=True): + blocks = [] + while n > 0 and self._fill_buffer(): + if n < len(self._buffer): + data = self._buffer[:n] + self._buffer = self._buffer[n:] + else: + data = self._buffer + self._buffer = None + if return_data: + blocks.append(data) + self._pos += len(data) + n -= len(data) + if return_data: + return b"".join(blocks) + + def peek(self, n=0): + """Return buffered data without advancing the file position. + + Always returns at least one byte of data, unless at EOF. + The exact number of bytes returned is unspecified. + """ + with self._lock: + self._check_can_read() + if self._mode == _MODE_READ_EOF or not self._fill_buffer(): + return b"" + return self._buffer + + def read(self, size=-1): + """Read up to size uncompressed bytes from the file. + + If size is negative or omitted, read until EOF is reached. + Returns b'' if the file is already at EOF. + """ + with self._lock: + self._check_can_read() + if self._mode == _MODE_READ_EOF or size == 0: + return b"" + elif size < 0: + return self._read_all() + else: + return self._read_block(size) + + def read1(self, size=-1): + """Read up to size uncompressed bytes with at most one read + from the underlying stream. + + Returns b'' if the file is at EOF. + """ + with self._lock: + self._check_can_read() + if (size == 0 or self._mode == _MODE_READ_EOF or + not self._fill_buffer()): + return b"" + if 0 < size < len(self._buffer): + data = self._buffer[:size] + self._buffer = self._buffer[size:] + else: + data = self._buffer + self._buffer = None + self._pos += len(data) + return data + + def readinto(self, b): + """Read up to len(b) bytes into b. + + Returns the number of bytes read (0 for EOF). + """ + with self._lock: + return io.BufferedIOBase.readinto(self, b) + + def readline(self, size=-1): + """Read a line of uncompressed bytes from the file. + + The terminating newline (if present) is retained. If size is + non-negative, no more than size bytes will be read (in which + case the line may be incomplete). Returns b'' if already at EOF. + """ + if not hasattr(size, "__index__"): + raise TypeError("Integer argument expected") + size = size.__index__() + with self._lock: + return io.BufferedIOBase.readline(self, size) + + def readlines(self, size=-1): + """Read a list of lines of uncompressed bytes from the file. + + size can be specified to control the number of lines read: no + further lines will be read once the total size of the lines read + so far equals or exceeds size. + """ + if not hasattr(size, "__index__"): + raise TypeError("Integer argument expected") + size = size.__index__() + with self._lock: + return io.BufferedIOBase.readlines(self, size) + + def write(self, data): + """Write a byte string to the file. + + Returns the number of uncompressed bytes written, which is + always len(data). Note that due to buffering, the file on disk + may not reflect the data written until close() is called. + """ + with self._lock: + self._check_can_write() + compressed = self._compressor.compress(data) + self._fp.write(compressed) + self._pos += len(data) + return len(data) + + def writelines(self, seq): + """Write a sequence of byte strings to the file. + + Returns the number of uncompressed bytes written. + seq can be any iterable yielding byte strings. + + Line separators are not added between the written byte strings. + """ + with self._lock: + return io.BufferedIOBase.writelines(self, seq) + + # Rewind the file to the beginning of the data stream. + def _rewind(self): + self._fp.seek(0, 0) + self._mode = _MODE_READ + self._pos = 0 + self._decompressor = BZ2Decompressor() + self._buffer = None + + def seek(self, offset, whence=0): + """Change the file position. + + The new position is specified by offset, relative to the + position indicated by whence. Values for whence are: + + 0: start of stream (default); offset must not be negative + 1: current stream position + 2: end of stream; offset must not be positive + + Returns the new file position. + + Note that seeking is emulated, so depending on the parameters, + this operation may be extremely slow. + """ + with self._lock: + self._check_can_seek() + + # Recalculate offset as an absolute file position. + if whence == 0: + pass + elif whence == 1: + offset = self._pos + offset + elif whence == 2: + # Seeking relative to EOF - we need to know the file's size. + if self._size < 0: + self._read_all(return_data=False) + offset = self._size + offset + else: + raise ValueError("Invalid value for whence: {}".format(whence)) + + # Make it so that offset is the number of bytes to skip forward. + if offset < self._pos: + self._rewind() + else: + offset -= self._pos + + # Read and discard data until we reach the desired position. + if self._mode != _MODE_READ_EOF: + self._read_block(offset, return_data=False) + + return self._pos + + def tell(self): + """Return the current file position.""" + with self._lock: + self._check_not_closed() + return self._pos + + +def compress(data, compresslevel=9): + """Compress a block of data. + + compresslevel, if given, must be a number between 1 and 9. + + For incremental compression, use a BZ2Compressor object instead. + """ + comp = BZ2Compressor(compresslevel) + return comp.compress(data) + comp.flush() + + +def decompress(data): + """Decompress a block of data. + + For incremental decompression, use a BZ2Decompressor object instead. + """ + if len(data) == 0: + return b"" + decomp = BZ2Decompressor() + result = decomp.decompress(data) + if not decomp.eof: + raise ValueError("Compressed data ended before the " + "end-of-stream marker was reached") + return result 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 @@ -21,7 +21,30 @@ class BaseTest(unittest.TestCase): "Base for other testcases." - TEXT = b'root:x:0:0:root:/root:/bin/bash\nbin:x:1:1:bin:/bin:\ndaemon:x:2:2:daemon:/sbin:\nadm:x:3:4:adm:/var/adm:\nlp:x:4:7:lp:/var/spool/lpd:\nsync:x:5:0:sync:/sbin:/bin/sync\nshutdown:x:6:0:shutdown:/sbin:/sbin/shutdown\nhalt:x:7:0:halt:/sbin:/sbin/halt\nmail:x:8:12:mail:/var/spool/mail:\nnews:x:9:13:news:/var/spool/news:\nuucp:x:10:14:uucp:/var/spool/uucp:\noperator:x:11:0:operator:/root:\ngames:x:12:100:games:/usr/games:\ngopher:x:13:30:gopher:/usr/lib/gopher-data:\nftp:x:14:50:FTP User:/var/ftp:/bin/bash\nnobody:x:65534:65534:Nobody:/home:\npostfix:x:100:101:postfix:/var/spool/postfix:\nniemeyer:x:500:500::/home/niemeyer:/bin/bash\npostgres:x:101:102:PostgreSQL Server:/var/lib/pgsql:/bin/bash\nmysql:x:102:103:MySQL server:/var/lib/mysql:/bin/bash\nwww:x:103:104::/var/www:/bin/false\n' + TEXT_LINES = [ + b'root:x:0:0:root:/root:/bin/bash\n', + b'bin:x:1:1:bin:/bin:\n', + b'daemon:x:2:2:daemon:/sbin:\n', + b'adm:x:3:4:adm:/var/adm:\n', + b'lp:x:4:7:lp:/var/spool/lpd:\n', + b'sync:x:5:0:sync:/sbin:/bin/sync\n', + b'shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown\n', + b'halt:x:7:0:halt:/sbin:/sbin/halt\n', + b'mail:x:8:12:mail:/var/spool/mail:\n', + b'news:x:9:13:news:/var/spool/news:\n', + b'uucp:x:10:14:uucp:/var/spool/uucp:\n', + b'operator:x:11:0:operator:/root:\n', + b'games:x:12:100:games:/usr/games:\n', + b'gopher:x:13:30:gopher:/usr/lib/gopher-data:\n', + b'ftp:x:14:50:FTP User:/var/ftp:/bin/bash\n', + b'nobody:x:65534:65534:Nobody:/home:\n', + b'postfix:x:100:101:postfix:/var/spool/postfix:\n', + b'niemeyer:x:500:500::/home/niemeyer:/bin/bash\n', + b'postgres:x:101:102:PostgreSQL Server:/var/lib/pgsql:/bin/bash\n', + b'mysql:x:102:103:MySQL server:/var/lib/mysql:/bin/bash\n', + b'www:x:103:104::/var/www:/bin/false\n', + ] + TEXT = b''.join(TEXT_LINES) DATA = b'BZh91AY&SY.\xc8N\x18\x00\x01>_\x80\x00\x10@\x02\xff\xf0\x01\x07n\x00?\xe7\xff\xe00\x01\x99\xaa\x00\xc0\x03F\x86\x8c#&\x83F\x9a\x03\x06\xa6\xd0\xa6\x93M\x0fQ\xa7\xa8\x06\x804hh\x12$\x11\xa4i4\xf14S\xd2\x88\xe5\xcd9gd6\x0b\n\xe9\x9b\xd5\x8a\x99\xf7\x08.K\x8ev\xfb\xf7xw\xbb\xdf\xa1\x92\xf1\xdd|/";\xa2\xba\x9f\xd5\xb1#A\xb6\xf6\xb3o\xc9\xc5y\\\xebO\xe7\x85\x9a\xbc\xb6f8\x952\xd5\xd7"%\x89>V,\xf7\xa6z\xe2\x9f\xa3\xdf\x11\x11"\xd6E)I\xa9\x13^\xca\xf3r\xd0\x03U\x922\xf26\xec\xb6\xed\x8b\xc3U\x13\x9d\xc5\x170\xa4\xfa^\x92\xacDF\x8a\x97\xd6\x19\xfe\xdd\xb8\xbd\x1a\x9a\x19\xa3\x80ankR\x8b\xe5\xd83]\xa9\xc6\x08\x82f\xf6\xb9"6l$\xb8j@\xc0\x8a\xb0l1..\xbak\x83ls\x15\xbc\xf4\xc1\x13\xbe\xf8E\xb8\x9d\r\xa8\x9dk\x84\xd3n\xfa\xacQ\x07\xb1%y\xaav\xb4\x08\xe0z\x1b\x16\xf5\x04\xe9\xcc\xb9\x08z\x1en7.G\xfc]\xc9\x14\xe1B@\xbb!8`' DATA_CRLF = b'BZh91AY&SY\xaez\xbbN\x00\x01H\xdf\x80\x00\x12@\x02\xff\xf0\x01\x07n\x00?\xe7\xff\xe0@\x01\xbc\xc6`\x86*\x8d=M\xa9\x9a\x86\xd0L@\x0fI\xa6!\xa1\x13\xc8\x88jdi\x8d@\x03@\x1a\x1a\x0c\x0c\x83 \x00\xc4h2\x19\x01\x82D\x84e\t\xe8\x99\x89\x19\x1ah\x00\r\x1a\x11\xaf\x9b\x0fG\xf5(\x1b\x1f?\t\x12\xcf\xb5\xfc\x95E\x00ps\x89\x12^\xa4\xdd\xa2&\x05(\x87\x04\x98\x89u\xe40%\xb6\x19\'\x8c\xc4\x89\xca\x07\x0e\x1b!\x91UIFU%C\x994!DI\xd2\xfa\xf0\xf1N8W\xde\x13A\xf5\x9cr%?\x9f3;I45A\xd1\x8bT\xb1\xa4\xc7\x8d\x1a\\"\xad\xa1\xabyBg\x15\xb9l\x88\x88\x91k"\x94\xa4\xd4\x89\xae*\xa6\x0b\x10\x0c\xd6\xd4m\xe86\xec\xb5j\x8a\x86j\';\xca.\x01I\xf2\xaaJ\xe8\x88\x8cU+t3\xfb\x0c\n\xa33\x13r2\r\x16\xe0\xb3(\xbf\x1d\x83r\xe7M\xf0D\x1365\xd8\x88\xd3\xa4\x92\xcb2\x06\x04\\\xc1\xb0\xea//\xbek&\xd8\xe6+t\xe5\xa1\x13\xada\x16\xder5"w]\xa2i\xb7[\x97R \xe2IT\xcd;Z\x04dk4\xad\x8a\t\xd3\x81z\x10\xf1:^`\xab\x1f\xc5\xdc\x91N\x14$+\x9e\xae\xd3\x80' @@ -54,13 +77,15 @@ if os.path.isfile(self.filename): os.unlink(self.filename) - def createTempFile(self, crlf=0): + def getData(self, crlf=False): + if crlf: + return self.DATA_CRLF + else: + return self.DATA + + def createTempFile(self, crlf=False): with open(self.filename, "wb") as f: - if crlf: - data = self.DATA_CRLF - else: - data = self.DATA - f.write(data) + f.write(self.getData(crlf)) def testRead(self): # "Test BZ2File.read()" @@ -70,7 +95,7 @@ self.assertEqual(bz2f.read(), self.TEXT) def testRead0(self): - # Test BBZ2File.read(0)" + # "Test BBZ2File.read(0)" self.createTempFile() with BZ2File(self.filename) as bz2f: self.assertRaises(TypeError, bz2f.read, None) @@ -94,6 +119,28 @@ with BZ2File(self.filename) as bz2f: self.assertEqual(bz2f.read(100), self.TEXT[:100]) + def testPeek(self): + # "Test BZ2File.peek()" + self.createTempFile() + with BZ2File(self.filename) as bz2f: + pdata = bz2f.peek() + self.assertNotEqual(len(pdata), 0) + self.assertTrue(self.TEXT.startswith(pdata)) + self.assertEqual(bz2f.read(), self.TEXT) + + def testReadInto(self): + # "Test BZ2File.readinto()" + self.createTempFile() + with BZ2File(self.filename) as bz2f: + n = 128 + b = bytearray(n) + self.assertEqual(bz2f.readinto(b), n) + self.assertEqual(b, self.TEXT[:n]) + n = len(self.TEXT) - n + b = bytearray(len(self.TEXT)) + self.assertEqual(bz2f.readinto(b), n) + self.assertEqual(b[:n], self.TEXT[-n:]) + def testReadLine(self): # "Test BZ2File.readline()" self.createTempFile() @@ -125,7 +172,7 @@ bz2f = BZ2File(self.filename) bz2f.close() self.assertRaises(ValueError, bz2f.__next__) - # This call will deadlock of the above .__next__ call failed to + # This call will deadlock if the above .__next__ call failed to # release the lock. self.assertRaises(ValueError, bz2f.readlines) @@ -217,6 +264,13 @@ self.assertEqual(bz2f.tell(), 0) self.assertEqual(bz2f.read(), self.TEXT) + def testFileno(self): + # "Test BZ2File.fileno()" + self.createTempFile() + with open(self.filename) as rawf: + with BZ2File(fileobj=rawf) as bz2f: + self.assertEqual(bz2f.fileno(), rawf.fileno()) + def testOpenDel(self): # "Test opening and deleting a file many times" self.createTempFile() @@ -278,17 +332,65 @@ t.join() def testMixedIterationReads(self): - # Issue #8397: mixed iteration and reads should be forbidden. - with bz2.BZ2File(self.filename, 'wb') as f: - # The internal buffer size is hard-wired to 8192 bytes, we must - # write out more than that for the test to stop half through - # the buffer. - f.write(self.TEXT * 100) - with bz2.BZ2File(self.filename, 'rb') as f: - next(f) - self.assertRaises(ValueError, f.read) - self.assertRaises(ValueError, f.readline) - self.assertRaises(ValueError, f.readlines) + # "Test mixed iteration and reads." + self.createTempFile() + linelen = len(self.TEXT_LINES[0]) + halflen = linelen // 2 + with bz2.BZ2File(self.filename) as bz2f: + bz2f.read(halflen) + self.assertEqual(next(bz2f), self.TEXT_LINES[0][halflen:]) + self.assertEqual(bz2f.read(), self.TEXT[linelen:]) + with bz2.BZ2File(self.filename) as bz2f: + bz2f.readline() + self.assertEqual(next(bz2f), self.TEXT_LINES[1]) + self.assertEqual(bz2f.readline(), self.TEXT_LINES[2]) + with bz2.BZ2File(self.filename) as bz2f: + bz2f.readlines() + with self.assertRaises(StopIteration): + next(bz2f) + self.assertEqual(bz2f.readlines(), []) + + def testReadBytesIO(self): + # "Test BZ2File.read() with BytesIO source" + with BytesIO(self.getData()) as bio: + with BZ2File(fileobj=bio) as bz2f: + self.assertRaises(TypeError, bz2f.read, None) + self.assertEqual(bz2f.read(), self.TEXT) + self.assertFalse(bio.closed) + + def testPeekBytesIO(self): + # "Test BZ2File.peek() with BytesIO source" + with BytesIO(self.getData()) as bio: + with BZ2File(fileobj=bio) as bz2f: + pdata = bz2f.peek() + self.assertNotEqual(len(pdata), 0) + self.assertTrue(self.TEXT.startswith(pdata)) + self.assertEqual(bz2f.read(), self.TEXT) + + def testWriteBytesIO(self): + # "Test BZ2File.write() with BytesIO destination" + with BytesIO() as bio: + with BZ2File(fileobj=bio, mode="w") as bz2f: + self.assertRaises(TypeError, bz2f.write) + bz2f.write(self.TEXT) + self.assertEqual(self.decompress(bio.getvalue()), self.TEXT) + self.assertFalse(bio.closed) + + def testSeekForwardBytesIO(self): + # "Test BZ2File.seek(150, 0) with BytesIO source" + with BytesIO(self.getData()) as bio: + with BZ2File(fileobj=bio) as bz2f: + self.assertRaises(TypeError, bz2f.seek) + bz2f.seek(150) + self.assertEqual(bz2f.read(), self.TEXT[150:]) + + def testSeekBackwardsBytesIO(self): + # "Test BZ2File.seek(-150, 1) with BytesIO source" + with BytesIO(self.getData()) as bio: + with BZ2File(fileobj=bio) as bz2f: + bz2f.read(500) + bz2f.seek(-150, 1) + self.assertEqual(bz2f.read(), self.TEXT[500-150:]) class BZ2CompressorTest(BaseTest): def testCompress(self): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -87,6 +87,10 @@ Library ------- +- Issue #5863: Rewrite BZ2File in pure Python, and allow it to accept + file-like objects using a new ``fileobj`` constructor argument. Patch by + Nadeem Vawda. + - unittest.TestCase.assertSameElements has been removed. - sys.getfilesystemencoding() raises a RuntimeError if initfsencoding() was not diff --git a/Modules/bz2module.c b/Modules/_bz2module.c rename from Modules/bz2module.c rename to Modules/_bz2module.c --- a/Modules/bz2module.c +++ b/Modules/_bz2module.c @@ -1,215 +1,111 @@ -/* +/* _bz2 - Low-level Python interface to libbzip2. */ -python-bz2 - python bz2 library interface - -Copyright (c) 2002 Gustavo Niemeyer -Copyright (c) 2002 Python Software Foundation; All Rights Reserved - -*/ +#define PY_SSIZE_T_CLEAN #include "Python.h" -#include -#include #include "structmember.h" #ifdef WITH_THREAD #include "pythread.h" #endif -static char __author__[] = -"The bz2 python module was written by:\n\ -\n\ - Gustavo Niemeyer \n\ -"; +#include +#include -/* Our very own off_t-like type, 64-bit if possible */ -/* copied from Objects/fileobject.c */ -#if !defined(HAVE_LARGEFILE_SUPPORT) -typedef off_t Py_off_t; -#elif SIZEOF_OFF_T >= 8 -typedef off_t Py_off_t; -#elif SIZEOF_FPOS_T >= 8 -typedef fpos_t Py_off_t; -#else -#error "Large file support, but neither off_t nor fpos_t is large enough." -#endif -#define BUF(v) PyBytes_AS_STRING(v) - -#define MODE_CLOSED 0 -#define MODE_READ 1 -#define MODE_READ_EOF 2 -#define MODE_WRITE 3 - -#define BZ2FileObject_Check(v) (Py_TYPE(v) == &BZ2File_Type) - - -#ifdef BZ_CONFIG_ERROR - -#if SIZEOF_LONG >= 8 -#define BZS_TOTAL_OUT(bzs) \ - (((long)bzs->total_out_hi32 << 32) + bzs->total_out_lo32) -#elif SIZEOF_LONG_LONG >= 8 -#define BZS_TOTAL_OUT(bzs) \ - (((PY_LONG_LONG)bzs->total_out_hi32 << 32) + bzs->total_out_lo32) -#else -#define BZS_TOTAL_OUT(bzs) \ - bzs->total_out_lo32 -#endif - -#else /* ! BZ_CONFIG_ERROR */ - -#define BZ2_bzRead bzRead -#define BZ2_bzReadOpen bzReadOpen -#define BZ2_bzReadClose bzReadClose -#define BZ2_bzWrite bzWrite -#define BZ2_bzWriteOpen bzWriteOpen -#define BZ2_bzWriteClose bzWriteClose +#ifndef BZ_CONFIG_ERROR #define BZ2_bzCompress bzCompress #define BZ2_bzCompressInit bzCompressInit #define BZ2_bzCompressEnd bzCompressEnd #define BZ2_bzDecompress bzDecompress #define BZ2_bzDecompressInit bzDecompressInit #define BZ2_bzDecompressEnd bzDecompressEnd - -#define BZS_TOTAL_OUT(bzs) bzs->total_out - -#endif /* ! BZ_CONFIG_ERROR */ +#endif /* ! BZ_CONFIG_ERROR */ #ifdef WITH_THREAD #define ACQUIRE_LOCK(obj) do { \ - if (!PyThread_acquire_lock(obj->lock, 0)) { \ + if (!PyThread_acquire_lock((obj)->lock, 0)) { \ Py_BEGIN_ALLOW_THREADS \ - PyThread_acquire_lock(obj->lock, 1); \ + PyThread_acquire_lock((obj)->lock, 1); \ Py_END_ALLOW_THREADS \ - } } while(0) -#define RELEASE_LOCK(obj) PyThread_release_lock(obj->lock) + } } while (0) +#define RELEASE_LOCK(obj) PyThread_release_lock((obj)->lock) #else #define ACQUIRE_LOCK(obj) #define RELEASE_LOCK(obj) #endif -/* Bits in f_newlinetypes */ -#define NEWLINE_UNKNOWN 0 /* No newline seen, yet */ -#define NEWLINE_CR 1 /* \r newline seen */ -#define NEWLINE_LF 2 /* \n newline seen */ -#define NEWLINE_CRLF 4 /* \r\n newline seen */ - -/* ===================================================================== */ -/* Structure definitions. */ - -typedef struct { - PyObject_HEAD - FILE *rawfp; - - char* f_buf; /* Allocated readahead buffer */ - char* f_bufend; /* Points after last occupied position */ - char* f_bufptr; /* Current buffer position */ - - BZFILE *fp; - int mode; - Py_off_t pos; - Py_off_t size; -#ifdef WITH_THREAD - PyThread_type_lock lock; -#endif -} BZ2FileObject; typedef struct { PyObject_HEAD bz_stream bzs; - int running; + int flushed; #ifdef WITH_THREAD PyThread_type_lock lock; #endif -} BZ2CompObject; +} BZ2Compressor; typedef struct { PyObject_HEAD bz_stream bzs; - int running; + char eof; /* T_BOOL expects a char */ PyObject *unused_data; #ifdef WITH_THREAD PyThread_type_lock lock; #endif -} BZ2DecompObject; +} BZ2Decompressor; -/* ===================================================================== */ -/* Utility functions. */ -/* Refuse regular I/O if there's data in the iteration-buffer. - * Mixing them would cause data to arrive out of order, as the read* - * methods don't use the iteration buffer. */ -static int -check_iterbuffered(BZ2FileObject *f) -{ - if (f->f_buf != NULL && - (f->f_bufend - f->f_bufptr) > 0 && - f->f_buf[0] != '\0') { - PyErr_SetString(PyExc_ValueError, - "Mixing iteration and read methods would lose data"); - return -1; - } - return 0; -} +/* Helper functions. */ static int -Util_CatchBZ2Error(int bzerror) +catch_bz2_error(int bzerror) { - int ret = 0; switch(bzerror) { case BZ_OK: + case BZ_RUN_OK: + case BZ_FLUSH_OK: + case BZ_FINISH_OK: case BZ_STREAM_END: - break; + return 0; #ifdef BZ_CONFIG_ERROR case BZ_CONFIG_ERROR: PyErr_SetString(PyExc_SystemError, - "the bz2 library was not compiled " - "correctly"); - ret = 1; - break; + "libbzip2 was not compiled correctly"); + return 1; #endif - case BZ_PARAM_ERROR: PyErr_SetString(PyExc_ValueError, - "the bz2 library has received wrong " - "parameters"); - ret = 1; - break; - + "Internal error - " + "invalid parameters passed to libbzip2"); + return 1; case BZ_MEM_ERROR: PyErr_NoMemory(); - ret = 1; - break; - + return 1; case BZ_DATA_ERROR: case BZ_DATA_ERROR_MAGIC: - PyErr_SetString(PyExc_IOError, "invalid data stream"); - ret = 1; - break; - + PyErr_SetString(PyExc_IOError, "Invalid data stream"); + return 1; case BZ_IO_ERROR: - PyErr_SetString(PyExc_IOError, "unknown IO error"); - ret = 1; - break; - + PyErr_SetString(PyExc_IOError, "Unknown I/O error"); + return 1; case BZ_UNEXPECTED_EOF: PyErr_SetString(PyExc_EOFError, - "compressed file ended before the " - "logical end-of-stream was detected"); - ret = 1; - break; - + "Compressed file ended before the logical " + "end-of-stream was detected"); + return 1; case BZ_SEQUENCE_ERROR: PyErr_SetString(PyExc_RuntimeError, - "wrong sequence of bz2 library " - "commands used"); - ret = 1; - break; + "Internal error - " + "Invalid sequence of commands sent to libbzip2"); + return 1; + default: + PyErr_Format(PyExc_IOError, + "Unrecognized error from libbzip2: %d", bzerror); + return 1; } - return ret; } #if BUFSIZ < 8192 @@ -224,1599 +120,316 @@ #define BIGCHUNK (512 * 1024) #endif -/* This is a hacked version of Python's fileobject.c:new_buffersize(). */ -static size_t -Util_NewBufferSize(size_t currentsize) +static int +grow_buffer(PyObject **buf) { - if (currentsize > SMALLCHUNK) { - /* Keep doubling until we reach BIGCHUNK; - then keep adding BIGCHUNK. */ - if (currentsize <= BIGCHUNK) - return currentsize + currentsize; - else - return currentsize + BIGCHUNK; - } - return currentsize + SMALLCHUNK; + size_t size = PyBytes_GET_SIZE(*buf); + if (size <= SMALLCHUNK) + return _PyBytes_Resize(buf, size + SMALLCHUNK); + else if (size <= BIGCHUNK) + return _PyBytes_Resize(buf, size * 2); + else + return _PyBytes_Resize(buf, size + BIGCHUNK); } -/* This is a hacked version of Python's fileobject.c:get_line(). */ + +/* BZ2Compressor class. */ + static PyObject * -Util_GetLine(BZ2FileObject *f, int n) +compress(BZ2Compressor *c, char *data, size_t len, int action) { - char c; - char *buf, *end; - size_t total_v_size; /* total # of slots in buffer */ - size_t used_v_size; /* # used slots in buffer */ - size_t increment; /* amount to increment the buffer */ - PyObject *v; - int bzerror; - int bytes_read; + size_t data_size = 0; + PyObject *result; - total_v_size = n > 0 ? n : 100; - v = PyBytes_FromStringAndSize((char *)NULL, total_v_size); - if (v == NULL) + result = PyBytes_FromStringAndSize(NULL, SMALLCHUNK); + if (result == NULL) return NULL; + c->bzs.next_in = data; + /* FIXME This is not 64-bit clean - avail_in is an int. */ + c->bzs.avail_in = len; + c->bzs.next_out = PyBytes_AS_STRING(result); + c->bzs.avail_out = PyBytes_GET_SIZE(result); + for (;;) { + char *this_out; + int bzerror; - buf = BUF(v); - end = buf + total_v_size; + Py_BEGIN_ALLOW_THREADS + this_out = c->bzs.next_out; + bzerror = BZ2_bzCompress(&c->bzs, action); + data_size += c->bzs.next_out - this_out; + Py_END_ALLOW_THREADS + if (catch_bz2_error(bzerror)) + goto error; - for (;;) { - Py_BEGIN_ALLOW_THREADS - do { - bytes_read = BZ2_bzRead(&bzerror, f->fp, &c, 1); - f->pos++; - if (bytes_read == 0) - break; - *buf++ = c; - } while (bzerror == BZ_OK && c != '\n' && buf != end); - Py_END_ALLOW_THREADS - if (bzerror == BZ_STREAM_END) { - f->size = f->pos; - f->mode = MODE_READ_EOF; + /* In regular compression mode, stop when input data is exhausted. + In flushing mode, stop when all buffered data has been flushed. */ + if ((action == BZ_RUN && c->bzs.avail_in == 0) || + (action == BZ_FINISH && bzerror == BZ_STREAM_END)) break; - } else if (bzerror != BZ_OK) { - Util_CatchBZ2Error(bzerror); - Py_DECREF(v); - return NULL; - } - if (c == '\n') - break; - /* Must be because buf == end */ - if (n > 0) - break; - used_v_size = total_v_size; - increment = total_v_size >> 2; /* mild exponential growth */ - total_v_size += increment; - if (total_v_size > INT_MAX) { - PyErr_SetString(PyExc_OverflowError, - "line is longer than a Python string can hold"); - Py_DECREF(v); - return NULL; - } - if (_PyBytes_Resize(&v, total_v_size) < 0) { - return NULL; - } - buf = BUF(v) + used_v_size; - end = BUF(v) + total_v_size; - } - used_v_size = buf - BUF(v); - if (used_v_size != total_v_size) { - if (_PyBytes_Resize(&v, used_v_size) < 0) { - v = NULL; + if (c->bzs.avail_out == 0) { + if (grow_buffer(&result) < 0) + goto error; + c->bzs.next_out = PyBytes_AS_STRING(result) + data_size; + c->bzs.avail_out = PyBytes_GET_SIZE(result) - data_size; } } - return v; + if (data_size != PyBytes_GET_SIZE(result)) + if (_PyBytes_Resize(&result, data_size) < 0) + goto error; + return result; + +error: + Py_XDECREF(result); + return NULL; } -/* This is a hacked version of Python's fileobject.c:drop_readahead(). */ -static void -Util_DropReadAhead(BZ2FileObject *f) +PyDoc_STRVAR(BZ2Compressor_compress__doc__, +"compress(data) -> bytes\n" +"\n" +"Provide data to the compressor object. Returns a chunk of\n" +"compressed data if possible, or b'' otherwise.\n" +"\n" +"When you have finished providing data to the compressor, call the\n" +"flush() method to finish the compression process.\n"); + +static PyObject * +BZ2Compressor_compress(BZ2Compressor *self, PyObject *args) { - if (f->f_buf != NULL) { - PyMem_Free(f->f_buf); - f->f_buf = NULL; - } -} + Py_buffer buffer; + PyObject *result = NULL; -/* This is a hacked version of Python's fileobject.c:readahead(). */ -static int -Util_ReadAhead(BZ2FileObject *f, int bufsize) -{ - int chunksize; - int bzerror; - - if (f->f_buf != NULL) { - if((f->f_bufend - f->f_bufptr) >= 1) - return 0; - else - Util_DropReadAhead(f); - } - if (f->mode == MODE_READ_EOF) { - f->f_bufptr = f->f_buf; - f->f_bufend = f->f_buf; - return 0; - } - if ((f->f_buf = PyMem_Malloc(bufsize)) == NULL) { - PyErr_NoMemory(); - return -1; - } - Py_BEGIN_ALLOW_THREADS - chunksize = BZ2_bzRead(&bzerror, f->fp, f->f_buf, bufsize); - Py_END_ALLOW_THREADS - f->pos += chunksize; - if (bzerror == BZ_STREAM_END) { - f->size = f->pos; - f->mode = MODE_READ_EOF; - } else if (bzerror != BZ_OK) { - Util_CatchBZ2Error(bzerror); - Util_DropReadAhead(f); - return -1; - } - f->f_bufptr = f->f_buf; - f->f_bufend = f->f_buf + chunksize; - return 0; -} - -/* This is a hacked version of Python's - * fileobject.c:readahead_get_line_skip(). */ -static PyBytesObject * -Util_ReadAheadGetLineSkip(BZ2FileObject *f, int skip, int bufsize) -{ - PyBytesObject* s; - char *bufptr; - char *buf; - int len; - - if (f->f_buf == NULL) - if (Util_ReadAhead(f, bufsize) < 0) - return NULL; - - len = f->f_bufend - f->f_bufptr; - if (len == 0) - return (PyBytesObject *) - PyBytes_FromStringAndSize(NULL, skip); - bufptr = memchr(f->f_bufptr, '\n', len); - if (bufptr != NULL) { - bufptr++; /* Count the '\n' */ - len = bufptr - f->f_bufptr; - s = (PyBytesObject *) - PyBytes_FromStringAndSize(NULL, skip+len); - if (s == NULL) - return NULL; - memcpy(PyBytes_AS_STRING(s)+skip, f->f_bufptr, len); - f->f_bufptr = bufptr; - if (bufptr == f->f_bufend) - Util_DropReadAhead(f); - } else { - bufptr = f->f_bufptr; - buf = f->f_buf; - f->f_buf = NULL; /* Force new readahead buffer */ - s = Util_ReadAheadGetLineSkip(f, skip+len, - bufsize + (bufsize>>2)); - if (s == NULL) { - PyMem_Free(buf); - return NULL; - } - memcpy(PyBytes_AS_STRING(s)+skip, bufptr, len); - PyMem_Free(buf); - } - return s; -} - -/* ===================================================================== */ -/* Methods of BZ2File. */ - -PyDoc_STRVAR(BZ2File_read__doc__, -"read([size]) -> string\n\ -\n\ -Read at most size uncompressed bytes, returned as a string. If the size\n\ -argument is negative or omitted, read until EOF is reached.\n\ -"); - -/* This is a hacked version of Python's fileobject.c:file_read(). */ -static PyObject * -BZ2File_read(BZ2FileObject *self, PyObject *args) -{ - long bytesrequested = -1; - size_t bytesread, buffersize, chunksize; - int bzerror; - PyObject *ret = NULL; - - if (!PyArg_ParseTuple(args, "|l:read", &bytesrequested)) + if (!PyArg_ParseTuple(args, "y*:compress", &buffer)) return NULL; ACQUIRE_LOCK(self); - switch (self->mode) { - case MODE_READ: - break; - case MODE_READ_EOF: - ret = PyBytes_FromStringAndSize("", 0); - goto cleanup; - case MODE_CLOSED: - PyErr_SetString(PyExc_ValueError, - "I/O operation on closed file"); - goto cleanup; - default: - PyErr_SetString(PyExc_IOError, - "file is not ready for reading"); - goto cleanup; - } - - /* refuse to mix with f.next() */ - if (check_iterbuffered(self)) - goto cleanup; - - if (bytesrequested < 0) - buffersize = Util_NewBufferSize((size_t)0); + if (self->flushed) + PyErr_SetString(PyExc_ValueError, "Compressor has been flushed"); else - buffersize = bytesrequested; - if (buffersize > INT_MAX) { - PyErr_SetString(PyExc_OverflowError, - "requested number of bytes is " - "more than a Python string can hold"); - goto cleanup; - } - ret = PyBytes_FromStringAndSize((char *)NULL, buffersize); - if (ret == NULL || buffersize == 0) - goto cleanup; - bytesread = 0; - - for (;;) { - Py_BEGIN_ALLOW_THREADS - chunksize = BZ2_bzRead(&bzerror, self->fp, - BUF(ret)+bytesread, - buffersize-bytesread); - self->pos += chunksize; - Py_END_ALLOW_THREADS - bytesread += chunksize; - if (bzerror == BZ_STREAM_END) { - self->size = self->pos; - self->mode = MODE_READ_EOF; - break; - } else if (bzerror != BZ_OK) { - Util_CatchBZ2Error(bzerror); - Py_DECREF(ret); - ret = NULL; - goto cleanup; - } - if (bytesrequested < 0) { - buffersize = Util_NewBufferSize(buffersize); - if (_PyBytes_Resize(&ret, buffersize) < 0) { - ret = NULL; - goto cleanup; - } - } else { - break; - } - } - if (bytesread != buffersize) { - if (_PyBytes_Resize(&ret, bytesread) < 0) { - ret = NULL; - } - } - -cleanup: + result = compress(self, buffer.buf, buffer.len, BZ_RUN); RELEASE_LOCK(self); - return ret; + PyBuffer_Release(&buffer); + return result; } -PyDoc_STRVAR(BZ2File_readline__doc__, -"readline([size]) -> string\n\ -\n\ -Return the next line from the file, as a string, retaining newline.\n\ -A non-negative size argument will limit the maximum number of bytes to\n\ -return (an incomplete line may be returned then). Return an empty\n\ -string at EOF.\n\ -"); +PyDoc_STRVAR(BZ2Compressor_flush__doc__, +"flush() -> bytes\n" +"\n" +"Finish the compression process. Returns the compressed data left\n" +"in internal buffers.\n" +"\n" +"The compressor object may not be used after this method is called.\n"); static PyObject * -BZ2File_readline(BZ2FileObject *self, PyObject *args) +BZ2Compressor_flush(BZ2Compressor *self, PyObject *noargs) { - PyObject *ret = NULL; - int sizehint = -1; - - if (!PyArg_ParseTuple(args, "|i:readline", &sizehint)) - return NULL; + PyObject *result = NULL; ACQUIRE_LOCK(self); - switch (self->mode) { - case MODE_READ: - break; - case MODE_READ_EOF: - ret = PyBytes_FromStringAndSize("", 0); - goto cleanup; - case MODE_CLOSED: - PyErr_SetString(PyExc_ValueError, - "I/O operation on closed file"); - goto cleanup; - default: - PyErr_SetString(PyExc_IOError, - "file is not ready for reading"); - goto cleanup; + if (self->flushed) + PyErr_SetString(PyExc_ValueError, "Repeated call to flush()"); + else { + self->flushed = 1; + result = compress(self, NULL, 0, BZ_FINISH); } - - /* refuse to mix with f.next() */ - if (check_iterbuffered(self)) - goto cleanup; - - if (sizehint == 0) - ret = PyBytes_FromStringAndSize("", 0); - else - ret = Util_GetLine(self, (sizehint < 0) ? 0 : sizehint); - -cleanup: RELEASE_LOCK(self); - return ret; + return result; } -PyDoc_STRVAR(BZ2File_readlines__doc__, -"readlines([size]) -> list\n\ -\n\ -Call readline() repeatedly and return a list of lines read.\n\ -The optional size argument, if given, is an approximate bound on the\n\ -total number of bytes in the lines returned.\n\ -"); - -/* This is a hacked version of Python's fileobject.c:file_readlines(). */ -static PyObject * -BZ2File_readlines(BZ2FileObject *self, PyObject *args) +static int +BZ2Compressor_init(BZ2Compressor *self, PyObject *args, PyObject *kwargs) { - long sizehint = 0; - PyObject *list = NULL; - PyObject *line; - char small_buffer[SMALLCHUNK]; - char *buffer = small_buffer; - size_t buffersize = SMALLCHUNK; - PyObject *big_buffer = NULL; - size_t nfilled = 0; - size_t nread; - size_t totalread = 0; - char *p, *q, *end; - int err; - int shortread = 0; + int compresslevel = 9; int bzerror; - if (!PyArg_ParseTuple(args, "|l:readlines", &sizehint)) - return NULL; - - ACQUIRE_LOCK(self); - switch (self->mode) { - case MODE_READ: - break; - case MODE_READ_EOF: - list = PyList_New(0); - goto cleanup; - case MODE_CLOSED: - PyErr_SetString(PyExc_ValueError, - "I/O operation on closed file"); - goto cleanup; - default: - PyErr_SetString(PyExc_IOError, - "file is not ready for reading"); - goto cleanup; - } - - /* refuse to mix with f.next() */ - if (check_iterbuffered(self)) - goto cleanup; - - if ((list = PyList_New(0)) == NULL) - goto cleanup; - - for (;;) { - Py_BEGIN_ALLOW_THREADS - nread = BZ2_bzRead(&bzerror, self->fp, - buffer+nfilled, buffersize-nfilled); - self->pos += nread; - Py_END_ALLOW_THREADS - if (bzerror == BZ_STREAM_END) { - self->size = self->pos; - self->mode = MODE_READ_EOF; - if (nread == 0) { - sizehint = 0; - break; - } - shortread = 1; - } else if (bzerror != BZ_OK) { - Util_CatchBZ2Error(bzerror); - error: - Py_DECREF(list); - list = NULL; - goto cleanup; - } - totalread += nread; - p = memchr(buffer+nfilled, '\n', nread); - if (!shortread && p == NULL) { - /* Need a larger buffer to fit this line */ - nfilled += nread; - buffersize *= 2; - if (buffersize > INT_MAX) { - PyErr_SetString(PyExc_OverflowError, - "line is longer than a Python string can hold"); - goto error; - } - if (big_buffer == NULL) { - /* Create the big buffer */ - big_buffer = PyBytes_FromStringAndSize( - NULL, buffersize); - if (big_buffer == NULL) - goto error; - buffer = PyBytes_AS_STRING(big_buffer); - memcpy(buffer, small_buffer, nfilled); - } - else { - /* Grow the big buffer */ - if (_PyBytes_Resize(&big_buffer, buffersize) < 0){ - big_buffer = NULL; - goto error; - } - buffer = PyBytes_AS_STRING(big_buffer); - } - continue; - } - end = buffer+nfilled+nread; - q = buffer; - while (p != NULL) { - /* Process complete lines */ - p++; - line = PyBytes_FromStringAndSize(q, p-q); - if (line == NULL) - goto error; - err = PyList_Append(list, line); - Py_DECREF(line); - if (err != 0) - goto error; - q = p; - p = memchr(q, '\n', end-q); - } - /* Move the remaining incomplete line to the start */ - nfilled = end-q; - memmove(buffer, q, nfilled); - if (sizehint > 0) - if (totalread >= (size_t)sizehint) - break; - if (shortread) { - sizehint = 0; - break; - } - } - if (nfilled != 0) { - /* Partial last line */ - line = PyBytes_FromStringAndSize(buffer, nfilled); - if (line == NULL) - goto error; - if (sizehint > 0) { - /* Need to complete the last line */ - PyObject *rest = Util_GetLine(self, 0); - if (rest == NULL) { - Py_DECREF(line); - goto error; - } - PyBytes_Concat(&line, rest); - Py_DECREF(rest); - if (line == NULL) - goto error; - } - err = PyList_Append(list, line); - Py_DECREF(line); - if (err != 0) - goto error; - } - - cleanup: - RELEASE_LOCK(self); - if (big_buffer) { - Py_DECREF(big_buffer); - } - return list; -} - -PyDoc_STRVAR(BZ2File_write__doc__, -"write(data) -> None\n\ -\n\ -Write the 'data' string to file. Note that due to buffering, close() may\n\ -be needed before the file on disk reflects the data written.\n\ -"); - -/* This is a hacked version of Python's fileobject.c:file_write(). */ -static PyObject * -BZ2File_write(BZ2FileObject *self, PyObject *args) -{ - PyObject *ret = NULL; - Py_buffer pbuf; - char *buf; - int len; - int bzerror; - - if (!PyArg_ParseTuple(args, "y*:write", &pbuf)) - return NULL; - buf = pbuf.buf; - len = pbuf.len; - - ACQUIRE_LOCK(self); - switch (self->mode) { - case MODE_WRITE: - break; - - case MODE_CLOSED: - PyErr_SetString(PyExc_ValueError, - "I/O operation on closed file"); - goto cleanup; - - default: - PyErr_SetString(PyExc_IOError, - "file is not ready for writing"); - goto cleanup; - } - - Py_BEGIN_ALLOW_THREADS - BZ2_bzWrite (&bzerror, self->fp, buf, len); - self->pos += len; - Py_END_ALLOW_THREADS - - if (bzerror != BZ_OK) { - Util_CatchBZ2Error(bzerror); - goto cleanup; - } - - Py_INCREF(Py_None); - ret = Py_None; - -cleanup: - PyBuffer_Release(&pbuf); - RELEASE_LOCK(self); - return ret; -} - -PyDoc_STRVAR(BZ2File_writelines__doc__, -"writelines(sequence_of_strings) -> None\n\ -\n\ -Write the sequence of strings to the file. Note that newlines are not\n\ -added. The sequence can be any iterable object producing strings. This is\n\ -equivalent to calling write() for each string.\n\ -"); - -/* This is a hacked version of Python's fileobject.c:file_writelines(). */ -static PyObject * -BZ2File_writelines(BZ2FileObject *self, PyObject *seq) -{ -#define CHUNKSIZE 1000 - PyObject *list = NULL; - PyObject *iter = NULL; - PyObject *ret = NULL; - PyObject *line; - int i, j, index, len, islist; - int bzerror; - - ACQUIRE_LOCK(self); - switch (self->mode) { - case MODE_WRITE: - break; - - case MODE_CLOSED: - PyErr_SetString(PyExc_ValueError, - "I/O operation on closed file"); - goto error; - - default: - PyErr_SetString(PyExc_IOError, - "file is not ready for writing"); - goto error; - } - - islist = PyList_Check(seq); - if (!islist) { - iter = PyObject_GetIter(seq); - if (iter == NULL) { - PyErr_SetString(PyExc_TypeError, - "writelines() requires an iterable argument"); - goto error; - } - list = PyList_New(CHUNKSIZE); - if (list == NULL) - goto error; - } - - /* Strategy: slurp CHUNKSIZE lines into a private list, - checking that they are all strings, then write that list - without holding the interpreter lock, then come back for more. */ - for (index = 0; ; index += CHUNKSIZE) { - if (islist) { - Py_XDECREF(list); - list = PyList_GetSlice(seq, index, index+CHUNKSIZE); - if (list == NULL) - goto error; - j = PyList_GET_SIZE(list); - } - else { - for (j = 0; j < CHUNKSIZE; j++) { - line = PyIter_Next(iter); - if (line == NULL) { - if (PyErr_Occurred()) - goto error; - break; - } - PyList_SetItem(list, j, line); - } - } - if (j == 0) - break; - - /* Check that all entries are indeed byte strings. If not, - apply the same rules as for file.write() and - convert the rets to strings. This is slow, but - seems to be the only way since all conversion APIs - could potentially execute Python code. */ - for (i = 0; i < j; i++) { - PyObject *v = PyList_GET_ITEM(list, i); - if (!PyBytes_Check(v)) { - const char *buffer; - Py_ssize_t len; - if (PyObject_AsCharBuffer(v, &buffer, &len)) { - PyErr_SetString(PyExc_TypeError, - "writelines() " - "argument must be " - "a sequence of " - "bytes objects"); - goto error; - } - line = PyBytes_FromStringAndSize(buffer, - len); - if (line == NULL) - goto error; - Py_DECREF(v); - PyList_SET_ITEM(list, i, line); - } - } - - /* Since we are releasing the global lock, the - following code may *not* execute Python code. */ - Py_BEGIN_ALLOW_THREADS - for (i = 0; i < j; i++) { - line = PyList_GET_ITEM(list, i); - len = PyBytes_GET_SIZE(line); - BZ2_bzWrite (&bzerror, self->fp, - PyBytes_AS_STRING(line), len); - if (bzerror != BZ_OK) { - Py_BLOCK_THREADS - Util_CatchBZ2Error(bzerror); - goto error; - } - } - Py_END_ALLOW_THREADS - - if (j < CHUNKSIZE) - break; - } - - Py_INCREF(Py_None); - ret = Py_None; - - error: - RELEASE_LOCK(self); - Py_XDECREF(list); - Py_XDECREF(iter); - return ret; -#undef CHUNKSIZE -} - -PyDoc_STRVAR(BZ2File_seek__doc__, -"seek(offset [, whence]) -> None\n\ -\n\ -Move to new file position. Argument offset is a byte count. Optional\n\ -argument whence defaults to 0 (offset from start of file, offset\n\ -should be >= 0); other values are 1 (move relative to current position,\n\ -positive or negative), and 2 (move relative to end of file, usually\n\ -negative, although many platforms allow seeking beyond the end of a file).\n\ -\n\ -Note that seeking of bz2 files is emulated, and depending on the parameters\n\ -the operation may be extremely slow.\n\ -"); - -static PyObject * -BZ2File_seek(BZ2FileObject *self, PyObject *args) -{ - int where = 0; - PyObject *offobj; - Py_off_t offset; - char small_buffer[SMALLCHUNK]; - char *buffer = small_buffer; - size_t buffersize = SMALLCHUNK; - Py_off_t bytesread = 0; - size_t readsize; - int chunksize; - int bzerror; - PyObject *ret = NULL; - - if (!PyArg_ParseTuple(args, "O|i:seek", &offobj, &where)) - return NULL; -#if !defined(HAVE_LARGEFILE_SUPPORT) - offset = PyLong_AsLong(offobj); -#else - offset = PyLong_Check(offobj) ? - PyLong_AsLongLong(offobj) : PyLong_AsLong(offobj); -#endif - if (PyErr_Occurred()) - return NULL; - - ACQUIRE_LOCK(self); - Util_DropReadAhead(self); - switch (self->mode) { - case MODE_READ: - case MODE_READ_EOF: - break; - - case MODE_CLOSED: - PyErr_SetString(PyExc_ValueError, - "I/O operation on closed file"); - goto cleanup; - - default: - PyErr_SetString(PyExc_IOError, - "seek works only while reading"); - goto cleanup; - } - - if (where == 2) { - if (self->size == -1) { - assert(self->mode != MODE_READ_EOF); - for (;;) { - Py_BEGIN_ALLOW_THREADS - chunksize = BZ2_bzRead(&bzerror, self->fp, - buffer, buffersize); - self->pos += chunksize; - Py_END_ALLOW_THREADS - - bytesread += chunksize; - if (bzerror == BZ_STREAM_END) { - break; - } else if (bzerror != BZ_OK) { - Util_CatchBZ2Error(bzerror); - goto cleanup; - } - } - self->mode = MODE_READ_EOF; - self->size = self->pos; - bytesread = 0; - } - offset = self->size + offset; - } else if (where == 1) { - offset = self->pos + offset; - } - - /* Before getting here, offset must be the absolute position the file - * pointer should be set to. */ - - if (offset >= self->pos) { - /* we can move forward */ - offset -= self->pos; - } else { - /* we cannot move back, so rewind the stream */ - BZ2_bzReadClose(&bzerror, self->fp); - if (bzerror != BZ_OK) { - Util_CatchBZ2Error(bzerror); - goto cleanup; - } - rewind(self->rawfp); - self->pos = 0; - self->fp = BZ2_bzReadOpen(&bzerror, self->rawfp, - 0, 0, NULL, 0); - if (bzerror != BZ_OK) { - Util_CatchBZ2Error(bzerror); - goto cleanup; - } - self->mode = MODE_READ; - } - - if (offset <= 0 || self->mode == MODE_READ_EOF) - goto exit; - - /* Before getting here, offset must be set to the number of bytes - * to walk forward. */ - for (;;) { - if (offset-bytesread > buffersize) - readsize = buffersize; - else - /* offset might be wider that readsize, but the result - * of the subtraction is bound by buffersize (see the - * condition above). buffersize is 8192. */ - readsize = (size_t)(offset-bytesread); - Py_BEGIN_ALLOW_THREADS - chunksize = BZ2_bzRead(&bzerror, self->fp, buffer, readsize); - self->pos += chunksize; - Py_END_ALLOW_THREADS - bytesread += chunksize; - if (bzerror == BZ_STREAM_END) { - self->size = self->pos; - self->mode = MODE_READ_EOF; - break; - } else if (bzerror != BZ_OK) { - Util_CatchBZ2Error(bzerror); - goto cleanup; - } - if (bytesread == offset) - break; - } - -exit: - Py_INCREF(Py_None); - ret = Py_None; - -cleanup: - RELEASE_LOCK(self); - return ret; -} - -PyDoc_STRVAR(BZ2File_tell__doc__, -"tell() -> int\n\ -\n\ -Return the current file position, an integer (may be a long integer).\n\ -"); - -static PyObject * -BZ2File_tell(BZ2FileObject *self, PyObject *args) -{ - PyObject *ret = NULL; - - if (self->mode == MODE_CLOSED) { - PyErr_SetString(PyExc_ValueError, - "I/O operation on closed file"); - goto cleanup; - } - -#if !defined(HAVE_LARGEFILE_SUPPORT) - ret = PyLong_FromLong(self->pos); -#else - ret = PyLong_FromLongLong(self->pos); -#endif - -cleanup: - return ret; -} - -PyDoc_STRVAR(BZ2File_close__doc__, -"close() -> None or (perhaps) an integer\n\ -\n\ -Close the file. Sets data attribute .closed to true. A closed file\n\ -cannot be used for further I/O operations. close() may be called more\n\ -than once without error.\n\ -"); - -static PyObject * -BZ2File_close(BZ2FileObject *self) -{ - PyObject *ret = NULL; - int bzerror = BZ_OK; - - if (self->mode == MODE_CLOSED) { - Py_RETURN_NONE; - } - - ACQUIRE_LOCK(self); - switch (self->mode) { - case MODE_READ: - case MODE_READ_EOF: - BZ2_bzReadClose(&bzerror, self->fp); - break; - case MODE_WRITE: - BZ2_bzWriteClose(&bzerror, self->fp, - 0, NULL, NULL); - break; - } - self->mode = MODE_CLOSED; - fclose(self->rawfp); - self->rawfp = NULL; - if (bzerror == BZ_OK) { - Py_INCREF(Py_None); - ret = Py_None; - } - else { - Util_CatchBZ2Error(bzerror); - } - - RELEASE_LOCK(self); - return ret; -} - -PyDoc_STRVAR(BZ2File_enter_doc, -"__enter__() -> self."); - -static PyObject * -BZ2File_enter(BZ2FileObject *self) -{ - if (self->mode == MODE_CLOSED) { - PyErr_SetString(PyExc_ValueError, - "I/O operation on closed file"); - return NULL; - } - Py_INCREF(self); - return (PyObject *) self; -} - -PyDoc_STRVAR(BZ2File_exit_doc, -"__exit__(*excinfo) -> None. Closes the file."); - -static PyObject * -BZ2File_exit(BZ2FileObject *self, PyObject *args) -{ - PyObject *ret = PyObject_CallMethod((PyObject *) self, "close", NULL); - if (!ret) - /* If error occurred, pass through */ - return NULL; - Py_DECREF(ret); - Py_RETURN_NONE; -} - - -static PyObject *BZ2File_getiter(BZ2FileObject *self); - -static PyMethodDef BZ2File_methods[] = { - {"read", (PyCFunction)BZ2File_read, METH_VARARGS, BZ2File_read__doc__}, - {"readline", (PyCFunction)BZ2File_readline, METH_VARARGS, BZ2File_readline__doc__}, - {"readlines", (PyCFunction)BZ2File_readlines, METH_VARARGS, BZ2File_readlines__doc__}, - {"write", (PyCFunction)BZ2File_write, METH_VARARGS, BZ2File_write__doc__}, - {"writelines", (PyCFunction)BZ2File_writelines, METH_O, BZ2File_writelines__doc__}, - {"seek", (PyCFunction)BZ2File_seek, METH_VARARGS, BZ2File_seek__doc__}, - {"tell", (PyCFunction)BZ2File_tell, METH_NOARGS, BZ2File_tell__doc__}, - {"close", (PyCFunction)BZ2File_close, METH_NOARGS, BZ2File_close__doc__}, - {"__enter__", (PyCFunction)BZ2File_enter, METH_NOARGS, BZ2File_enter_doc}, - {"__exit__", (PyCFunction)BZ2File_exit, METH_VARARGS, BZ2File_exit_doc}, - {NULL, NULL} /* sentinel */ -}; - - -/* ===================================================================== */ -/* Getters and setters of BZ2File. */ - -static PyObject * -BZ2File_get_closed(BZ2FileObject *self, void *closure) -{ - return PyLong_FromLong(self->mode == MODE_CLOSED); -} - -static PyGetSetDef BZ2File_getset[] = { - {"closed", (getter)BZ2File_get_closed, NULL, - "True if the file is closed"}, - {NULL} /* Sentinel */ -}; - - -/* ===================================================================== */ -/* Slot definitions for BZ2File_Type. */ - -static int -BZ2File_init(BZ2FileObject *self, PyObject *args, PyObject *kwargs) -{ - static char *kwlist[] = {"filename", "mode", "buffering", - "compresslevel", 0}; - PyObject *name_obj = NULL; - char *name; - char *mode = "r"; - int buffering = -1; - int compresslevel = 9; - int bzerror; - int mode_char = 0; - - self->size = -1; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&|sii:BZ2File", - kwlist, PyUnicode_FSConverter, &name_obj, - &mode, &buffering, - &compresslevel)) + if (!PyArg_ParseTuple(args, "|i:BZ2Compressor", &compresslevel)) return -1; - - name = PyBytes_AsString(name_obj); - if (compresslevel < 1 || compresslevel > 9) { + if (!(1 <= compresslevel && compresslevel <= 9)) { PyErr_SetString(PyExc_ValueError, "compresslevel must be between 1 and 9"); - Py_DECREF(name_obj); return -1; } - for (;;) { - int error = 0; - switch (*mode) { - case 'r': - case 'w': - if (mode_char) - error = 1; - mode_char = *mode; - break; - - case 'b': - break; - - default: - error = 1; - break; - } - if (error) { - PyErr_Format(PyExc_ValueError, - "invalid mode char %c", *mode); - Py_DECREF(name_obj); - return -1; - } - mode++; - if (*mode == '\0') - break; - } - - if (mode_char == 0) { - mode_char = 'r'; - } - - mode = (mode_char == 'r') ? "rb" : "wb"; - - self->rawfp = fopen(name, mode); - Py_DECREF(name_obj); - if (self->rawfp == NULL) { - PyErr_SetFromErrno(PyExc_IOError); - return -1; - } - /* XXX Ignore buffering */ - - /* From now on, we have stuff to dealloc, so jump to error label - * instead of returning */ - #ifdef WITH_THREAD self->lock = PyThread_allocate_lock(); - if (!self->lock) { - PyErr_SetString(PyExc_MemoryError, "unable to allocate lock"); - goto error; + if (self->lock == NULL) { + PyErr_SetString(PyExc_MemoryError, "Unable to allocate lock"); + return -1; } #endif - if (mode_char == 'r') - self->fp = BZ2_bzReadOpen(&bzerror, self->rawfp, - 0, 0, NULL, 0); - else - self->fp = BZ2_bzWriteOpen(&bzerror, self->rawfp, - compresslevel, 0, 0); - - if (bzerror != BZ_OK) { - Util_CatchBZ2Error(bzerror); + bzerror = BZ2_bzCompressInit(&self->bzs, compresslevel, 0, 0); + if (catch_bz2_error(bzerror)) goto error; - } - - self->mode = (mode_char == 'r') ? MODE_READ : MODE_WRITE; return 0; error: - fclose(self->rawfp); - self->rawfp = NULL; #ifdef WITH_THREAD - if (self->lock) { - PyThread_free_lock(self->lock); - self->lock = NULL; - } + PyThread_free_lock(self->lock); + self->lock = NULL; #endif return -1; } static void -BZ2File_dealloc(BZ2FileObject *self) +BZ2Compressor_dealloc(BZ2Compressor *self) { - int bzerror; + BZ2_bzCompressEnd(&self->bzs); #ifdef WITH_THREAD - if (self->lock) + if (self->lock != NULL) PyThread_free_lock(self->lock); #endif - switch (self->mode) { - case MODE_READ: - case MODE_READ_EOF: - BZ2_bzReadClose(&bzerror, self->fp); - break; - case MODE_WRITE: - BZ2_bzWriteClose(&bzerror, self->fp, - 0, NULL, NULL); - break; - } - Util_DropReadAhead(self); - if (self->rawfp != NULL) - fclose(self->rawfp); Py_TYPE(self)->tp_free((PyObject *)self); } -/* This is a hacked version of Python's fileobject.c:file_getiter(). */ -static PyObject * -BZ2File_getiter(BZ2FileObject *self) -{ - if (self->mode == MODE_CLOSED) { - PyErr_SetString(PyExc_ValueError, - "I/O operation on closed file"); - return NULL; - } - Py_INCREF((PyObject*)self); - return (PyObject *)self; -} - -/* This is a hacked version of Python's fileobject.c:file_iternext(). */ -#define READAHEAD_BUFSIZE 8192 -static PyObject * -BZ2File_iternext(BZ2FileObject *self) -{ - PyBytesObject* ret; - ACQUIRE_LOCK(self); - if (self->mode == MODE_CLOSED) { - RELEASE_LOCK(self); - PyErr_SetString(PyExc_ValueError, - "I/O operation on closed file"); - return NULL; - } - ret = Util_ReadAheadGetLineSkip(self, 0, READAHEAD_BUFSIZE); - RELEASE_LOCK(self); - if (ret == NULL || PyBytes_GET_SIZE(ret) == 0) { - Py_XDECREF(ret); - return NULL; - } - return (PyObject *)ret; -} - -/* ===================================================================== */ -/* BZ2File_Type definition. */ - -PyDoc_VAR(BZ2File__doc__) = -PyDoc_STR( -"BZ2File(name [, mode='r', buffering=0, compresslevel=9]) -> file object\n\ -\n\ -Open a bz2 file. The mode can be 'r' or 'w', for reading (default) or\n\ -writing. When opened for writing, the file will be created if it doesn't\n\ -exist, and truncated otherwise. If the buffering argument is given, 0 means\n\ -unbuffered, and larger numbers specify the buffer size. If compresslevel\n\ -is given, must be a number between 1 and 9.\n\ -Data read is always returned in bytes; data written ought to be bytes.\n\ -"); - -static PyTypeObject BZ2File_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "bz2.BZ2File", /*tp_name*/ - sizeof(BZ2FileObject), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - (destructor)BZ2File_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_reserved*/ - 0, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash*/ - 0, /*tp_call*/ - 0, /*tp_str*/ - PyObject_GenericGetAttr,/*tp_getattro*/ - PyObject_GenericSetAttr,/*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/ - BZ2File__doc__, /*tp_doc*/ - 0, /*tp_traverse*/ - 0, /*tp_clear*/ - 0, /*tp_richcompare*/ - 0, /*tp_weaklistoffset*/ - (getiterfunc)BZ2File_getiter, /*tp_iter*/ - (iternextfunc)BZ2File_iternext, /*tp_iternext*/ - BZ2File_methods, /*tp_methods*/ - 0, /*tp_members*/ - BZ2File_getset, /*tp_getset*/ - 0, /*tp_base*/ - 0, /*tp_dict*/ - 0, /*tp_descr_get*/ - 0, /*tp_descr_set*/ - 0, /*tp_dictoffset*/ - (initproc)BZ2File_init, /*tp_init*/ - PyType_GenericAlloc, /*tp_alloc*/ - PyType_GenericNew, /*tp_new*/ - PyObject_Free, /*tp_free*/ - 0, /*tp_is_gc*/ +static PyMethodDef BZ2Compressor_methods[] = { + {"compress", (PyCFunction)BZ2Compressor_compress, METH_VARARGS, + BZ2Compressor_compress__doc__}, + {"flush", (PyCFunction)BZ2Compressor_flush, METH_NOARGS, + BZ2Compressor_flush__doc__}, + {NULL} }; +PyDoc_STRVAR(BZ2Compressor__doc__, +"BZ2Compressor(compresslevel=9)\n" +"\n" +"Create a compressor object for compressing data incrementally.\n" +"\n" +"compresslevel, if given, must be a number between 1 and 9.\n" +"\n" +"For one-shot compression, use the compress() function instead.\n"); -/* ===================================================================== */ -/* Methods of BZ2Comp. */ +static PyTypeObject BZ2Compressor_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "_bz2.BZ2Compressor", /* tp_name */ + sizeof(BZ2Compressor), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)BZ2Compressor_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_reserved */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + BZ2Compressor__doc__, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + BZ2Compressor_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 */ + (initproc)BZ2Compressor_init, /* tp_init */ + 0, /* tp_alloc */ + PyType_GenericNew, /* tp_new */ +}; -PyDoc_STRVAR(BZ2Comp_compress__doc__, -"compress(data) -> string\n\ -\n\ -Provide more data to the compressor object. It will return chunks of\n\ -compressed data whenever possible. When you've finished providing data\n\ -to compress, call the flush() method to finish the compression process,\n\ -and return what is left in the internal buffers.\n\ -"); + +/* BZ2Decompressor class. */ static PyObject * -BZ2Comp_compress(BZ2CompObject *self, PyObject *args) +decompress(BZ2Decompressor *d, char *data, size_t len) { - Py_buffer pdata; - char *data; - int datasize; - int bufsize = SMALLCHUNK; - PY_LONG_LONG totalout; - PyObject *ret = NULL; - bz_stream *bzs = &self->bzs; - int bzerror; + size_t data_size = 0; + PyObject *result; - if (!PyArg_ParseTuple(args, "y*:compress", &pdata)) - return NULL; - data = pdata.buf; - datasize = pdata.len; + result = PyBytes_FromStringAndSize(NULL, SMALLCHUNK); + if (result == NULL) + return result; + d->bzs.next_in = data; + /* FIXME This is not 64-bit clean - avail_in is an int. */ + d->bzs.avail_in = len; + d->bzs.next_out = PyBytes_AS_STRING(result); + d->bzs.avail_out = PyBytes_GET_SIZE(result); + for (;;) { + char *this_out; + int bzerror; - if (datasize == 0) { - PyBuffer_Release(&pdata); - return PyBytes_FromStringAndSize("", 0); - } - - ACQUIRE_LOCK(self); - if (!self->running) { - PyErr_SetString(PyExc_ValueError, - "this object was already flushed"); - goto error; - } - - ret = PyBytes_FromStringAndSize(NULL, bufsize); - if (!ret) - goto error; - - bzs->next_in = data; - bzs->avail_in = datasize; - bzs->next_out = BUF(ret); - bzs->avail_out = bufsize; - - totalout = BZS_TOTAL_OUT(bzs); - - for (;;) { Py_BEGIN_ALLOW_THREADS - bzerror = BZ2_bzCompress(bzs, BZ_RUN); + this_out = d->bzs.next_out; + bzerror = BZ2_bzDecompress(&d->bzs); + data_size += d->bzs.next_out - this_out; Py_END_ALLOW_THREADS - if (bzerror != BZ_RUN_OK) { - Util_CatchBZ2Error(bzerror); + if (catch_bz2_error(bzerror)) goto error; + if (bzerror == BZ_STREAM_END) { + d->eof = 1; + if (d->bzs.avail_in > 0) { /* Save leftover input to unused_data */ + Py_CLEAR(d->unused_data); + d->unused_data = PyBytes_FromStringAndSize(d->bzs.next_in, + d->bzs.avail_in); + if (d->unused_data == NULL) + goto error; + } + break; } - if (bzs->avail_in == 0) - break; /* no more input data */ - if (bzs->avail_out == 0) { - bufsize = Util_NewBufferSize(bufsize); - if (_PyBytes_Resize(&ret, bufsize) < 0) { - BZ2_bzCompressEnd(bzs); + if (d->bzs.avail_in == 0) + break; + if (d->bzs.avail_out == 0) { + if (grow_buffer(&result) < 0) goto error; - } - bzs->next_out = BUF(ret) + (BZS_TOTAL_OUT(bzs) - - totalout); - bzs->avail_out = bufsize - (bzs->next_out - BUF(ret)); + d->bzs.next_out = PyBytes_AS_STRING(result) + data_size; + d->bzs.avail_out = PyBytes_GET_SIZE(result) - data_size; } } - - if (_PyBytes_Resize(&ret, - (Py_ssize_t)(BZS_TOTAL_OUT(bzs) - totalout)) < 0) - goto error; - - RELEASE_LOCK(self); - PyBuffer_Release(&pdata); - return ret; + if (data_size != PyBytes_GET_SIZE(result)) + if (_PyBytes_Resize(&result, data_size) < 0) + goto error; + return result; error: - RELEASE_LOCK(self); - PyBuffer_Release(&pdata); - Py_XDECREF(ret); + Py_XDECREF(result); return NULL; } -PyDoc_STRVAR(BZ2Comp_flush__doc__, -"flush() -> string\n\ -\n\ -Finish the compression process and return what is left in internal buffers.\n\ -You must not use the compressor object after calling this method.\n\ -"); +PyDoc_STRVAR(BZ2Decompressor_decompress__doc__, +"decompress(data) -> bytes\n" +"\n" +"Provide data to the decompressor object. Returns a chunk of\n" +"decompressed data if possible, or b'' otherwise.\n" +"\n" +"Attempting to decompress data after the end of stream is reached\n" +"raises an EOFError. Any data found after the end of the stream\n" +"is ignored and saved in the unused_data attribute.\n"); static PyObject * -BZ2Comp_flush(BZ2CompObject *self) +BZ2Decompressor_decompress(BZ2Decompressor *self, PyObject *args) { - int bufsize = SMALLCHUNK; - PyObject *ret = NULL; - bz_stream *bzs = &self->bzs; - PY_LONG_LONG totalout; - int bzerror; + Py_buffer buffer; + PyObject *result = NULL; + + if (!PyArg_ParseTuple(args, "y*:decompress", &buffer)) + return NULL; ACQUIRE_LOCK(self); - if (!self->running) { - PyErr_SetString(PyExc_ValueError, "object was already " - "flushed"); - goto error; - } - self->running = 0; - - ret = PyBytes_FromStringAndSize(NULL, bufsize); - if (!ret) - goto error; - - bzs->next_out = BUF(ret); - bzs->avail_out = bufsize; - - totalout = BZS_TOTAL_OUT(bzs); - - for (;;) { - Py_BEGIN_ALLOW_THREADS - bzerror = BZ2_bzCompress(bzs, BZ_FINISH); - Py_END_ALLOW_THREADS - if (bzerror == BZ_STREAM_END) { - break; - } else if (bzerror != BZ_FINISH_OK) { - Util_CatchBZ2Error(bzerror); - goto error; - } - if (bzs->avail_out == 0) { - bufsize = Util_NewBufferSize(bufsize); - if (_PyBytes_Resize(&ret, bufsize) < 0) - goto error; - bzs->next_out = BUF(ret); - bzs->next_out = BUF(ret) + (BZS_TOTAL_OUT(bzs) - - totalout); - bzs->avail_out = bufsize - (bzs->next_out - BUF(ret)); - } - } - - if (bzs->avail_out != 0) { - if (_PyBytes_Resize(&ret, - (Py_ssize_t)(BZS_TOTAL_OUT(bzs) - totalout)) < 0) - goto error; - } - + if (self->eof) + PyErr_SetString(PyExc_EOFError, "End of stream already reached"); + else + result = decompress(self, buffer.buf, buffer.len); RELEASE_LOCK(self); - return ret; - -error: - RELEASE_LOCK(self); - Py_XDECREF(ret); - return NULL; + PyBuffer_Release(&buffer); + return result; } -static PyMethodDef BZ2Comp_methods[] = { - {"compress", (PyCFunction)BZ2Comp_compress, METH_VARARGS, - BZ2Comp_compress__doc__}, - {"flush", (PyCFunction)BZ2Comp_flush, METH_NOARGS, - BZ2Comp_flush__doc__}, - {NULL, NULL} /* sentinel */ -}; - - -/* ===================================================================== */ -/* Slot definitions for BZ2Comp_Type. */ - static int -BZ2Comp_init(BZ2CompObject *self, PyObject *args, PyObject *kwargs) -{ - int compresslevel = 9; - int bzerror; - static char *kwlist[] = {"compresslevel", 0}; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i:BZ2Compressor", - kwlist, &compresslevel)) - return -1; - - if (compresslevel < 1 || compresslevel > 9) { - PyErr_SetString(PyExc_ValueError, - "compresslevel must be between 1 and 9"); - goto error; - } - -#ifdef WITH_THREAD - self->lock = PyThread_allocate_lock(); - if (!self->lock) { - PyErr_SetString(PyExc_MemoryError, "unable to allocate lock"); - goto error; - } -#endif - - memset(&self->bzs, 0, sizeof(bz_stream)); - bzerror = BZ2_bzCompressInit(&self->bzs, compresslevel, 0, 0); - if (bzerror != BZ_OK) { - Util_CatchBZ2Error(bzerror); - goto error; - } - - self->running = 1; - - return 0; -error: -#ifdef WITH_THREAD - if (self->lock) { - PyThread_free_lock(self->lock); - self->lock = NULL; - } -#endif - return -1; -} - -static void -BZ2Comp_dealloc(BZ2CompObject *self) -{ -#ifdef WITH_THREAD - if (self->lock) - PyThread_free_lock(self->lock); -#endif - BZ2_bzCompressEnd(&self->bzs); - Py_TYPE(self)->tp_free((PyObject *)self); -} - - -/* ===================================================================== */ -/* BZ2Comp_Type definition. */ - -PyDoc_STRVAR(BZ2Comp__doc__, -"BZ2Compressor([compresslevel=9]) -> compressor object\n\ -\n\ -Create a new compressor object. This object may be used to compress\n\ -data sequentially. If you want to compress data in one shot, use the\n\ -compress() function instead. The compresslevel parameter, if given,\n\ -must be a number between 1 and 9.\n\ -"); - -static PyTypeObject BZ2Comp_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "bz2.BZ2Compressor", /*tp_name*/ - sizeof(BZ2CompObject), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - (destructor)BZ2Comp_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_reserved*/ - 0, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash*/ - 0, /*tp_call*/ - 0, /*tp_str*/ - PyObject_GenericGetAttr,/*tp_getattro*/ - PyObject_GenericSetAttr,/*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/ - BZ2Comp__doc__, /*tp_doc*/ - 0, /*tp_traverse*/ - 0, /*tp_clear*/ - 0, /*tp_richcompare*/ - 0, /*tp_weaklistoffset*/ - 0, /*tp_iter*/ - 0, /*tp_iternext*/ - BZ2Comp_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*/ - (initproc)BZ2Comp_init, /*tp_init*/ - PyType_GenericAlloc, /*tp_alloc*/ - PyType_GenericNew, /*tp_new*/ - PyObject_Free, /*tp_free*/ - 0, /*tp_is_gc*/ -}; - - -/* ===================================================================== */ -/* Members of BZ2Decomp. */ - -#undef OFF -#define OFF(x) offsetof(BZ2DecompObject, x) - -static PyMemberDef BZ2Decomp_members[] = { - {"unused_data", T_OBJECT, OFF(unused_data), READONLY}, - {NULL} /* Sentinel */ -}; - - -/* ===================================================================== */ -/* Methods of BZ2Decomp. */ - -PyDoc_STRVAR(BZ2Decomp_decompress__doc__, -"decompress(data) -> string\n\ -\n\ -Provide more data to the decompressor object. It will return chunks\n\ -of decompressed data whenever possible. If you try to decompress data\n\ -after the end of stream is found, EOFError will be raised. If any data\n\ -was found after the end of stream, it'll be ignored and saved in\n\ -unused_data attribute.\n\ -"); - -static PyObject * -BZ2Decomp_decompress(BZ2DecompObject *self, PyObject *args) -{ - Py_buffer pdata; - char *data; - int datasize; - int bufsize = SMALLCHUNK; - PY_LONG_LONG totalout; - PyObject *ret = NULL; - bz_stream *bzs = &self->bzs; - int bzerror; - - if (!PyArg_ParseTuple(args, "y*:decompress", &pdata)) - return NULL; - data = pdata.buf; - datasize = pdata.len; - - ACQUIRE_LOCK(self); - if (!self->running) { - PyErr_SetString(PyExc_EOFError, "end of stream was " - "already found"); - goto error; - } - - ret = PyBytes_FromStringAndSize(NULL, bufsize); - if (!ret) - goto error; - - bzs->next_in = data; - bzs->avail_in = datasize; - bzs->next_out = BUF(ret); - bzs->avail_out = bufsize; - - totalout = BZS_TOTAL_OUT(bzs); - - for (;;) { - Py_BEGIN_ALLOW_THREADS - bzerror = BZ2_bzDecompress(bzs); - Py_END_ALLOW_THREADS - if (bzerror == BZ_STREAM_END) { - if (bzs->avail_in != 0) { - Py_DECREF(self->unused_data); - self->unused_data = - PyBytes_FromStringAndSize(bzs->next_in, - bzs->avail_in); - } - self->running = 0; - break; - } - if (bzerror != BZ_OK) { - Util_CatchBZ2Error(bzerror); - goto error; - } - if (bzs->avail_in == 0) - break; /* no more input data */ - if (bzs->avail_out == 0) { - bufsize = Util_NewBufferSize(bufsize); - if (_PyBytes_Resize(&ret, bufsize) < 0) { - BZ2_bzDecompressEnd(bzs); - goto error; - } - bzs->next_out = BUF(ret); - bzs->next_out = BUF(ret) + (BZS_TOTAL_OUT(bzs) - - totalout); - bzs->avail_out = bufsize - (bzs->next_out - BUF(ret)); - } - } - - if (bzs->avail_out != 0) { - if (_PyBytes_Resize(&ret, - (Py_ssize_t)(BZS_TOTAL_OUT(bzs) - totalout)) < 0) - goto error; - } - - RELEASE_LOCK(self); - PyBuffer_Release(&pdata); - return ret; - -error: - RELEASE_LOCK(self); - PyBuffer_Release(&pdata); - Py_XDECREF(ret); - return NULL; -} - -static PyMethodDef BZ2Decomp_methods[] = { - {"decompress", (PyCFunction)BZ2Decomp_decompress, METH_VARARGS, BZ2Decomp_decompress__doc__}, - {NULL, NULL} /* sentinel */ -}; - - -/* ===================================================================== */ -/* Slot definitions for BZ2Decomp_Type. */ - -static int -BZ2Decomp_init(BZ2DecompObject *self, PyObject *args, PyObject *kwargs) +BZ2Decompressor_init(BZ2Decompressor *self, PyObject *args, PyObject *kwargs) { int bzerror; @@ -1825,325 +438,120 @@ #ifdef WITH_THREAD self->lock = PyThread_allocate_lock(); - if (!self->lock) { - PyErr_SetString(PyExc_MemoryError, "unable to allocate lock"); - goto error; + if (self->lock == NULL) { + PyErr_SetString(PyExc_MemoryError, "Unable to allocate lock"); + return -1; } #endif self->unused_data = PyBytes_FromStringAndSize("", 0); - if (!self->unused_data) + if (self->unused_data == NULL) goto error; - memset(&self->bzs, 0, sizeof(bz_stream)); bzerror = BZ2_bzDecompressInit(&self->bzs, 0, 0); - if (bzerror != BZ_OK) { - Util_CatchBZ2Error(bzerror); + if (catch_bz2_error(bzerror)) goto error; - } - - self->running = 1; return 0; error: + Py_CLEAR(self->unused_data); #ifdef WITH_THREAD - if (self->lock) { - PyThread_free_lock(self->lock); - self->lock = NULL; - } + PyThread_free_lock(self->lock); + self->lock = NULL; #endif - Py_CLEAR(self->unused_data); return -1; } static void -BZ2Decomp_dealloc(BZ2DecompObject *self) +BZ2Decompressor_dealloc(BZ2Decompressor *self) { + BZ2_bzDecompressEnd(&self->bzs); + Py_CLEAR(self->unused_data); #ifdef WITH_THREAD - if (self->lock) + if (self->lock != NULL) PyThread_free_lock(self->lock); #endif - Py_XDECREF(self->unused_data); - BZ2_bzDecompressEnd(&self->bzs); Py_TYPE(self)->tp_free((PyObject *)self); } - -/* ===================================================================== */ -/* BZ2Decomp_Type definition. */ - -PyDoc_STRVAR(BZ2Decomp__doc__, -"BZ2Decompressor() -> decompressor object\n\ -\n\ -Create a new decompressor object. This object may be used to decompress\n\ -data sequentially. If you want to decompress data in one shot, use the\n\ -decompress() function instead.\n\ -"); - -static PyTypeObject BZ2Decomp_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "bz2.BZ2Decompressor", /*tp_name*/ - sizeof(BZ2DecompObject), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - (destructor)BZ2Decomp_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_reserved*/ - 0, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash*/ - 0, /*tp_call*/ - 0, /*tp_str*/ - PyObject_GenericGetAttr,/*tp_getattro*/ - PyObject_GenericSetAttr,/*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/ - BZ2Decomp__doc__, /*tp_doc*/ - 0, /*tp_traverse*/ - 0, /*tp_clear*/ - 0, /*tp_richcompare*/ - 0, /*tp_weaklistoffset*/ - 0, /*tp_iter*/ - 0, /*tp_iternext*/ - BZ2Decomp_methods, /*tp_methods*/ - BZ2Decomp_members, /*tp_members*/ - 0, /*tp_getset*/ - 0, /*tp_base*/ - 0, /*tp_dict*/ - 0, /*tp_descr_get*/ - 0, /*tp_descr_set*/ - 0, /*tp_dictoffset*/ - (initproc)BZ2Decomp_init, /*tp_init*/ - PyType_GenericAlloc, /*tp_alloc*/ - PyType_GenericNew, /*tp_new*/ - PyObject_Free, /*tp_free*/ - 0, /*tp_is_gc*/ +static PyMethodDef BZ2Decompressor_methods[] = { + {"decompress", (PyCFunction)BZ2Decompressor_decompress, METH_VARARGS, + BZ2Decompressor_decompress__doc__}, + {NULL} }; +PyDoc_STRVAR(BZ2Decompressor_eof__doc__, +"True if the end-of-stream marker has been reached."); -/* ===================================================================== */ -/* Module functions. */ +PyDoc_STRVAR(BZ2Decompressor_unused_data__doc__, +"Data found after the end of the compressed stream."); -PyDoc_STRVAR(bz2_compress__doc__, -"compress(data [, compresslevel=9]) -> string\n\ -\n\ -Compress data in one shot. If you want to compress data sequentially,\n\ -use an instance of BZ2Compressor instead. The compresslevel parameter, if\n\ -given, must be a number between 1 and 9.\n\ -"); - -static PyObject * -bz2_compress(PyObject *self, PyObject *args, PyObject *kwargs) -{ - int compresslevel=9; - Py_buffer pdata; - char *data; - int datasize; - int bufsize; - PyObject *ret = NULL; - bz_stream _bzs; - bz_stream *bzs = &_bzs; - int bzerror; - static char *kwlist[] = {"data", "compresslevel", 0}; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "y*|i", - kwlist, &pdata, - &compresslevel)) - return NULL; - data = pdata.buf; - datasize = pdata.len; - - if (compresslevel < 1 || compresslevel > 9) { - PyErr_SetString(PyExc_ValueError, - "compresslevel must be between 1 and 9"); - PyBuffer_Release(&pdata); - return NULL; - } - - /* Conforming to bz2 manual, this is large enough to fit compressed - * data in one shot. We will check it later anyway. */ - bufsize = datasize + (datasize/100+1) + 600; - - ret = PyBytes_FromStringAndSize(NULL, bufsize); - if (!ret) { - PyBuffer_Release(&pdata); - return NULL; - } - - memset(bzs, 0, sizeof(bz_stream)); - - bzs->next_in = data; - bzs->avail_in = datasize; - bzs->next_out = BUF(ret); - bzs->avail_out = bufsize; - - bzerror = BZ2_bzCompressInit(bzs, compresslevel, 0, 0); - if (bzerror != BZ_OK) { - Util_CatchBZ2Error(bzerror); - PyBuffer_Release(&pdata); - Py_DECREF(ret); - return NULL; - } - - for (;;) { - Py_BEGIN_ALLOW_THREADS - bzerror = BZ2_bzCompress(bzs, BZ_FINISH); - Py_END_ALLOW_THREADS - if (bzerror == BZ_STREAM_END) { - break; - } else if (bzerror != BZ_FINISH_OK) { - BZ2_bzCompressEnd(bzs); - Util_CatchBZ2Error(bzerror); - PyBuffer_Release(&pdata); - Py_DECREF(ret); - return NULL; - } - if (bzs->avail_out == 0) { - bufsize = Util_NewBufferSize(bufsize); - if (_PyBytes_Resize(&ret, bufsize) < 0) { - BZ2_bzCompressEnd(bzs); - PyBuffer_Release(&pdata); - return NULL; - } - bzs->next_out = BUF(ret) + BZS_TOTAL_OUT(bzs); - bzs->avail_out = bufsize - (bzs->next_out - BUF(ret)); - } - } - - if (bzs->avail_out != 0) { - if (_PyBytes_Resize(&ret, (Py_ssize_t)BZS_TOTAL_OUT(bzs)) < 0) { - ret = NULL; - } - } - BZ2_bzCompressEnd(bzs); - - PyBuffer_Release(&pdata); - return ret; -} - -PyDoc_STRVAR(bz2_decompress__doc__, -"decompress(data) -> decompressed data\n\ -\n\ -Decompress data in one shot. If you want to decompress data sequentially,\n\ -use an instance of BZ2Decompressor instead.\n\ -"); - -static PyObject * -bz2_decompress(PyObject *self, PyObject *args) -{ - Py_buffer pdata; - char *data; - int datasize; - int bufsize = SMALLCHUNK; - PyObject *ret; - bz_stream _bzs; - bz_stream *bzs = &_bzs; - int bzerror; - - if (!PyArg_ParseTuple(args, "y*:decompress", &pdata)) - return NULL; - data = pdata.buf; - datasize = pdata.len; - - if (datasize == 0) { - PyBuffer_Release(&pdata); - return PyBytes_FromStringAndSize("", 0); - } - - ret = PyBytes_FromStringAndSize(NULL, bufsize); - if (!ret) { - PyBuffer_Release(&pdata); - return NULL; - } - - memset(bzs, 0, sizeof(bz_stream)); - - bzs->next_in = data; - bzs->avail_in = datasize; - bzs->next_out = BUF(ret); - bzs->avail_out = bufsize; - - bzerror = BZ2_bzDecompressInit(bzs, 0, 0); - if (bzerror != BZ_OK) { - Util_CatchBZ2Error(bzerror); - Py_DECREF(ret); - PyBuffer_Release(&pdata); - return NULL; - } - - for (;;) { - Py_BEGIN_ALLOW_THREADS - bzerror = BZ2_bzDecompress(bzs); - Py_END_ALLOW_THREADS - if (bzerror == BZ_STREAM_END) { - break; - } else if (bzerror != BZ_OK) { - BZ2_bzDecompressEnd(bzs); - Util_CatchBZ2Error(bzerror); - PyBuffer_Release(&pdata); - Py_DECREF(ret); - return NULL; - } - if (bzs->avail_in == 0) { - BZ2_bzDecompressEnd(bzs); - PyErr_SetString(PyExc_ValueError, - "couldn't find end of stream"); - PyBuffer_Release(&pdata); - Py_DECREF(ret); - return NULL; - } - if (bzs->avail_out == 0) { - bufsize = Util_NewBufferSize(bufsize); - if (_PyBytes_Resize(&ret, bufsize) < 0) { - BZ2_bzDecompressEnd(bzs); - PyBuffer_Release(&pdata); - return NULL; - } - bzs->next_out = BUF(ret) + BZS_TOTAL_OUT(bzs); - bzs->avail_out = bufsize - (bzs->next_out - BUF(ret)); - } - } - - if (bzs->avail_out != 0) { - if (_PyBytes_Resize(&ret, (Py_ssize_t)BZS_TOTAL_OUT(bzs)) < 0) { - ret = NULL; - } - } - BZ2_bzDecompressEnd(bzs); - PyBuffer_Release(&pdata); - - return ret; -} - -static PyMethodDef bz2_methods[] = { - {"compress", (PyCFunction) bz2_compress, METH_VARARGS|METH_KEYWORDS, - bz2_compress__doc__}, - {"decompress", (PyCFunction) bz2_decompress, METH_VARARGS, - bz2_decompress__doc__}, - {NULL, NULL} /* sentinel */ +static PyMemberDef BZ2Decompressor_members[] = { + {"eof", T_BOOL, offsetof(BZ2Decompressor, eof), + READONLY, BZ2Decompressor_eof__doc__}, + {"unused_data", T_OBJECT_EX, offsetof(BZ2Decompressor, unused_data), + READONLY, BZ2Decompressor_unused_data__doc__}, + {NULL} }; -/* ===================================================================== */ -/* Initialization function. */ +PyDoc_STRVAR(BZ2Decompressor__doc__, +"BZ2Decompressor()\n" +"\n" +"Create a decompressor object for decompressing data incrementally.\n" +"\n" +"For one-shot decompression, use the decompress() function instead.\n"); -PyDoc_STRVAR(bz2__doc__, -"The python bz2 module provides a comprehensive interface for\n\ -the bz2 compression library. It implements a complete file\n\ -interface, one shot (de)compression functions, and types for\n\ -sequential (de)compression.\n\ -"); +static PyTypeObject BZ2Decompressor_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "_bz2.BZ2Decompressor", /* tp_name */ + sizeof(BZ2Decompressor), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)BZ2Decompressor_dealloc,/* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_reserved */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + BZ2Decompressor__doc__, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + BZ2Decompressor_methods, /* tp_methods */ + BZ2Decompressor_members, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)BZ2Decompressor_init, /* tp_init */ + 0, /* tp_alloc */ + PyType_GenericNew, /* tp_new */ +}; -static struct PyModuleDef bz2module = { +/* Module initialization. */ + +static struct PyModuleDef _bz2module = { PyModuleDef_HEAD_INIT, - "bz2", - bz2__doc__, + "_bz2", + NULL, -1, - bz2_methods, + NULL, NULL, NULL, NULL, @@ -2151,30 +559,25 @@ }; PyMODINIT_FUNC -PyInit_bz2(void) +PyInit__bz2(void) { PyObject *m; - if (PyType_Ready(&BZ2File_Type) < 0) + if (PyType_Ready(&BZ2Compressor_Type) < 0) return NULL; - if (PyType_Ready(&BZ2Comp_Type) < 0) - return NULL; - if (PyType_Ready(&BZ2Decomp_Type) < 0) + if (PyType_Ready(&BZ2Decompressor_Type) < 0) return NULL; - m = PyModule_Create(&bz2module); + m = PyModule_Create(&_bz2module); if (m == NULL) return NULL; - PyModule_AddObject(m, "__author__", PyUnicode_FromString(__author__)); + Py_INCREF(&BZ2Compressor_Type); + PyModule_AddObject(m, "BZ2Compressor", (PyObject *)&BZ2Compressor_Type); - Py_INCREF(&BZ2File_Type); - PyModule_AddObject(m, "BZ2File", (PyObject *)&BZ2File_Type); + Py_INCREF(&BZ2Decompressor_Type); + PyModule_AddObject(m, "BZ2Decompressor", + (PyObject *)&BZ2Decompressor_Type); - Py_INCREF(&BZ2Comp_Type); - PyModule_AddObject(m, "BZ2Compressor", (PyObject *)&BZ2Comp_Type); - - Py_INCREF(&BZ2Decomp_Type); - PyModule_AddObject(m, "BZ2Decompressor", (PyObject *)&BZ2Decomp_Type); return m; } diff --git a/PCbuild/bz2.vcproj b/PCbuild/_bz2.vcproj rename from PCbuild/bz2.vcproj rename to PCbuild/_bz2.vcproj --- a/PCbuild/bz2.vcproj +++ b/PCbuild/_bz2.vcproj @@ -2,7 +2,7 @@ diff --git a/PCbuild/pcbuild.sln b/PCbuild/pcbuild.sln --- a/PCbuild/pcbuild.sln +++ b/PCbuild/pcbuild.sln @@ -87,7 +87,7 @@ {CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26} = {CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26} EndProjectSection EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bz2", "bz2.vcproj", "{73FCD2BD-F133-46B7-8EC1-144CD82A59D5}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "_bz2", "_bz2.vcproj", "{73FCD2BD-F133-46B7-8EC1-144CD82A59D5}" ProjectSection(ProjectDependencies) = postProject {CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26} = {CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26} EndProjectSection diff --git a/PCbuild/readme.txt b/PCbuild/readme.txt --- a/PCbuild/readme.txt +++ b/PCbuild/readme.txt @@ -112,9 +112,9 @@ pre-built Tcl/Tk in either ..\..\tcltk for 32-bit or ..\..\tcltk64 for 64-bit (relative to this directory). See below for instructions to build Tcl/Tk. -bz2 - Python wrapper for the libbz2 compression library. Homepage - http://sources.redhat.com/bzip2/ +_bz2 + Python wrapper for the libbzip2 compression library. Homepage + http://www.bzip.org/ Download the source from the python.org copy into the dist directory: diff --git a/setup.py b/setup.py --- a/setup.py +++ b/setup.py @@ -1233,11 +1233,11 @@ bz2_extra_link_args = ('-Wl,-search_paths_first',) else: bz2_extra_link_args = () - exts.append( Extension('bz2', ['bz2module.c'], + exts.append( Extension('_bz2', ['_bz2module.c'], libraries = ['bz2'], extra_link_args = bz2_extra_link_args) ) else: - missing.append('bz2') + missing.append('_bz2') # Interface to the Expat XML parser # -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Apr 3 17:09:11 2011 From: python-checkins at python.org (antoine.pitrou) Date: Sun, 03 Apr 2011 17:09:11 +0200 Subject: [Python-checkins] cpython: Fix whitespace Message-ID: http://hg.python.org/cpython/rev/ff105faf1bac changeset: 69113:ff105faf1bac user: Antoine Pitrou date: Sun Apr 03 17:08:49 2011 +0200 summary: Fix whitespace files: Lib/bz2.py | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/bz2.py b/Lib/bz2.py --- a/Lib/bz2.py +++ b/Lib/bz2.py @@ -105,7 +105,7 @@ self._fp.write(self._compressor.flush()) self._compressor = None finally: - try: + try: if self._closefp: self._fp.close() finally: @@ -251,7 +251,7 @@ def readinto(self, b): """Read up to len(b) bytes into b. - + Returns the number of bytes read (0 for EOF). """ with self._lock: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Apr 3 18:20:19 2011 From: python-checkins at python.org (antoine.pitrou) Date: Sun, 03 Apr 2011 18:20:19 +0200 Subject: [Python-checkins] cpython (3.2): Issue #11746: Fix SSLContext.load_cert_chain() to accept elliptic curve private Message-ID: http://hg.python.org/cpython/rev/88ed3de28520 changeset: 69114:88ed3de28520 branch: 3.2 parent: 69109:1fd736395df3 user: Antoine Pitrou date: Sun Apr 03 18:15:34 2011 +0200 summary: Issue #11746: Fix SSLContext.load_cert_chain() to accept elliptic curve private keys. files: Misc/NEWS | 3 +++ Modules/_ssl.c | 2 +- 2 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -49,6 +49,9 @@ Library ------- +- Issue #11746: Fix SSLContext.load_cert_chain() to accept elliptic curve + private keys. + - sys.getfilesystemencoding() raises a RuntimeError if initfsencoding() was not called yet: detect bootstrap (startup) issues earlier. diff --git a/Modules/_ssl.c b/Modules/_ssl.c --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -1623,7 +1623,7 @@ goto error; } PySSL_BEGIN_ALLOW_THREADS - r = SSL_CTX_use_RSAPrivateKey_file(self->ctx, + r = SSL_CTX_use_PrivateKey_file(self->ctx, PyBytes_AS_STRING(keyfile ? keyfile_bytes : certfile_bytes), SSL_FILETYPE_PEM); PySSL_END_ALLOW_THREADS -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Apr 3 18:20:20 2011 From: python-checkins at python.org (antoine.pitrou) Date: Sun, 03 Apr 2011 18:20:20 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge fix for issue #11746 Message-ID: http://hg.python.org/cpython/rev/c11e05a60d36 changeset: 69115:c11e05a60d36 parent: 69113:ff105faf1bac parent: 69114:88ed3de28520 user: Antoine Pitrou date: Sun Apr 03 18:16:50 2011 +0200 summary: Merge fix for issue #11746 files: Misc/NEWS | 3 +++ Modules/_ssl.c | 2 +- 2 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -87,6 +87,9 @@ Library ------- +- Issue #11746: Fix SSLContext.load_cert_chain() to accept elliptic curve + private keys. + - Issue #5863: Rewrite BZ2File in pure Python, and allow it to accept file-like objects using a new ``fileobj`` constructor argument. Patch by Nadeem Vawda. diff --git a/Modules/_ssl.c b/Modules/_ssl.c --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -1620,7 +1620,7 @@ goto error; } PySSL_BEGIN_ALLOW_THREADS - r = SSL_CTX_use_RSAPrivateKey_file(self->ctx, + r = SSL_CTX_use_PrivateKey_file(self->ctx, PyBytes_AS_STRING(keyfile ? keyfile_bytes : certfile_bytes), SSL_FILETYPE_PEM); PySSL_END_ALLOW_THREADS -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Apr 3 18:29:49 2011 From: python-checkins at python.org (antoine.pitrou) Date: Sun, 03 Apr 2011 18:29:49 +0200 Subject: [Python-checkins] cpython: Issue #11748: try to fix sporadic failures in test_ftplib Message-ID: http://hg.python.org/cpython/rev/8a2d848244a2 changeset: 69116:8a2d848244a2 user: Antoine Pitrou date: Sun Apr 03 18:29:45 2011 +0200 summary: Issue #11748: try to fix sporadic failures in test_ftplib files: Lib/test/test_ftplib.py | 22 ++++++++++++++++------ 1 files changed, 16 insertions(+), 6 deletions(-) diff --git a/Lib/test/test_ftplib.py b/Lib/test/test_ftplib.py --- a/Lib/test/test_ftplib.py +++ b/Lib/test/test_ftplib.py @@ -611,16 +611,26 @@ def test_source_address(self): self.client.quit() port = support.find_unused_port() - self.client.connect(self.server.host, self.server.port, - source_address=(HOST, port)) - self.assertEqual(self.client.sock.getsockname()[1], port) - self.client.quit() + try: + self.client.connect(self.server.host, self.server.port, + source_address=(HOST, port)) + self.assertEqual(self.client.sock.getsockname()[1], port) + self.client.quit() + except IOError as e: + if e.errno == errno.EADDRINUSE: + self.skipTest("couldn't bind to port %d" % port) + raise def test_source_address_passive_connection(self): port = support.find_unused_port() self.client.source_address = (HOST, port) - with self.client.transfercmd('list') as sock: - self.assertEqual(sock.getsockname()[1], port) + try: + with self.client.transfercmd('list') as sock: + self.assertEqual(sock.getsockname()[1], port) + except IOError as e: + if e.errno == errno.EADDRINUSE: + self.skipTest("couldn't bind to port %d" % port) + raise def test_parse257(self): self.assertEqual(ftplib.parse257('257 "/foo/bar"'), '/foo/bar') -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Apr 3 18:46:26 2011 From: python-checkins at python.org (victor.stinner) Date: Sun, 03 Apr 2011 18:46:26 +0200 Subject: [Python-checkins] cpython: test_faulthandler: fix regex on the check_dump_traceback_threads() traceback Message-ID: http://hg.python.org/cpython/rev/cb169f61785b changeset: 69117:cb169f61785b user: Victor Stinner date: Sun Apr 03 18:41:22 2011 +0200 summary: test_faulthandler: fix regex on the check_dump_traceback_threads() traceback The traceback may contain "_is_owned": Thread 0x40962b90: File "/srv/buildbot/buildarea/3.x.bolen-ubuntu/build/Lib/threading.py", line 220 in _is_owned File "/srv/buildbot/buildarea/3.x.bolen-ubuntu/build/Lib/threading.py", line 227 in wait File "/srv/buildbot/buildarea/3.x.bolen-ubuntu/build/Lib/threading.py", line 421 in wait File "", line 23 in run File "/srv/buildbot/buildarea/3.x.bolen-ubuntu/build/Lib/threading.py", line 735 in _bootstrap_inner File "/srv/buildbot/buildarea/3.x.bolen-ubuntu/build/Lib/threading.py", line 708 in _bootstrap Current thread XXX: File "", line 10 in dump File "", line 28 in files: Lib/test/test_faulthandler.py | 5 ++--- 1 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_faulthandler.py b/Lib/test/test_faulthandler.py --- a/Lib/test/test_faulthandler.py +++ b/Lib/test/test_faulthandler.py @@ -325,9 +325,8 @@ lineno = 10 regex = """ ^Thread 0x[0-9a-f]+: -(?: File ".*threading.py", line [0-9]+ in wait -)? File ".*threading.py", line [0-9]+ in wait - File "", line 23 in run +(?: File ".*threading.py", line [0-9]+ in [_a-z]+ +){{1,3}} File "", line 23 in run File ".*threading.py", line [0-9]+ in _bootstrap_inner File ".*threading.py", line [0-9]+ in _bootstrap -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Apr 3 18:46:28 2011 From: python-checkins at python.org (victor.stinner) Date: Sun, 03 Apr 2011 18:46:28 +0200 Subject: [Python-checkins] cpython: test_faulthandler: improve the test on dump_tracebacks_later(cancel=True) Message-ID: http://hg.python.org/cpython/rev/2d0a855ce30a changeset: 69118:2d0a855ce30a user: Victor Stinner date: Sun Apr 03 18:45:42 2011 +0200 summary: test_faulthandler: improve the test on dump_tracebacks_later(cancel=True) files: Lib/test/test_faulthandler.py | 33 ++++++++++------------ 1 files changed, 15 insertions(+), 18 deletions(-) diff --git a/Lib/test/test_faulthandler.py b/Lib/test/test_faulthandler.py --- a/Lib/test/test_faulthandler.py +++ b/Lib/test/test_faulthandler.py @@ -358,25 +358,19 @@ import time def func(repeat, cancel, timeout): + if cancel: + faulthandler.cancel_dump_tracebacks_later() + pause = timeout * 2.5 # on Windows XP, b-a gives 1.249931 after sleep(1.25) min_pause = pause * 0.9 a = time.time() time.sleep(pause) + b = time.time() faulthandler.cancel_dump_tracebacks_later() - b = time.time() # Check that sleep() was not interrupted assert (b - a) >= min_pause, "{{}} < {{}}".format(b - a, min_pause) - if cancel: - pause = timeout * 1.5 - min_pause = pause * 0.9 - a = time.time() - time.sleep(pause) - b = time.time() - # Check that sleep() was not interrupted - assert (b - a) >= min_pause, "{{}} < {{}}".format(b - a, min_pause) - timeout = {timeout} repeat = {repeat} cancel = {cancel} @@ -400,13 +394,16 @@ trace, exitcode = self.get_output(code, filename) trace = '\n'.join(trace) - if repeat: - count = 2 + if not cancel: + if repeat: + count = 2 + else: + count = 1 + header = 'Thread 0x[0-9a-f]+:\n' + regex = expected_traceback(12, 27, header, count=count) + self.assertRegex(trace, regex) else: - count = 1 - header = 'Thread 0x[0-9a-f]+:\n' - regex = expected_traceback(9, 33, header, count=count) - self.assertRegex(trace, regex) + self.assertEqual(trace, '') self.assertEqual(exitcode, 0) @unittest.skipIf(not hasattr(faulthandler, 'dump_tracebacks_later'), @@ -425,8 +422,8 @@ def test_dump_tracebacks_later_repeat(self): self.check_dump_tracebacks_later(repeat=True) - def test_dump_tracebacks_later_repeat_cancel(self): - self.check_dump_tracebacks_later(repeat=True, cancel=True) + def test_dump_tracebacks_later_cancel(self): + self.check_dump_tracebacks_later(cancel=True) def test_dump_tracebacks_later_file(self): self.check_dump_tracebacks_later(file=True) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Apr 3 23:46:44 2011 From: python-checkins at python.org (victor.stinner) Date: Sun, 03 Apr 2011 23:46:44 +0200 Subject: [Python-checkins] cpython: Issue #11727, issue #11753, issue #11755: disable regrtest timeout Message-ID: http://hg.python.org/cpython/rev/394f0ea0d29e changeset: 69119:394f0ea0d29e user: Victor Stinner date: Sun Apr 03 23:46:42 2011 +0200 summary: Issue #11727, issue #11753, issue #11755: disable regrtest timeout Disable regrtest timeout until #11753 and #11755 are fixed files: Lib/test/regrtest.py | 2 +- Misc/NEWS | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -240,7 +240,7 @@ findleaks=False, use_resources=None, trace=False, coverdir='coverage', runleaks=False, huntrleaks=False, verbose2=False, print_slow=False, random_seed=None, use_mp=None, verbose3=False, forever=False, - header=False, timeout=30*60): + header=False, timeout=None): """Execute a test suite. This also parses command-line options and modifies its behavior diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -370,9 +370,8 @@ Tests ----- -- Issue #11727: If a test takes more than 30 minutes, regrtest dumps the - traceback of all threads and exits. Use --timeout option to change the - default timeout or to disable it. +- Issue #11727: Add a --timeout option to regrtest: if a test takes more than + TIMEOUT seconds, dumps the traceback of all threads and exits. - Issue #11653: fix -W with -j in regrtest. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 4 00:13:06 2011 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 04 Apr 2011 00:13:06 +0200 Subject: [Python-checkins] cpython: Issue #11688: Add sqlite3.Connection.set_trace_callback(). Patch by Torsten Message-ID: http://hg.python.org/cpython/rev/575ee55081dc changeset: 69120:575ee55081dc user: Antoine Pitrou date: Mon Apr 04 00:12:04 2011 +0200 summary: Issue #11688: Add sqlite3.Connection.set_trace_callback(). Patch by Torsten Landschoff. files: Doc/library/sqlite3.rst | 16 ++++++ Lib/sqlite3/test/hooks.py | 48 ++++++++++++++++++- Misc/NEWS | 3 + Modules/_sqlite/connection.c | 62 ++++++++++++++++++++++++ 4 files changed, 128 insertions(+), 1 deletions(-) diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -369,6 +369,22 @@ method with :const:`None` for *handler*. +.. method:: Connection.set_trace_callback(trace_callback) + + Registers *trace_callback* to be called for each SQL statement that is + actually executed by the SQLite backend. + + The only argument passed to the callback is the statement (as string) that + is being executed. The return value of the callback is ignored. Note that + the backend does not only run statements passed to the :meth:`Cursor.execute` + methods. Other sources include the transaction management of the Python + module and the execution of triggers defined in the current database. + + Passing :const:`None` as *trace_callback* will disable the trace callback. + + .. versionadded:: 3.3 + + .. method:: Connection.enable_load_extension(enabled) This routine allows/disallows the SQLite engine to load SQLite extensions diff --git a/Lib/sqlite3/test/hooks.py b/Lib/sqlite3/test/hooks.py --- a/Lib/sqlite3/test/hooks.py +++ b/Lib/sqlite3/test/hooks.py @@ -175,10 +175,56 @@ con.execute("select 1 union select 2 union select 3").fetchall() self.assertEqual(action, 0, "progress handler was not cleared") +class TraceCallbackTests(unittest.TestCase): + def CheckTraceCallbackUsed(self): + """ + Test that the trace callback is invoked once it is set. + """ + con = sqlite.connect(":memory:") + traced_statements = [] + def trace(statement): + traced_statements.append(statement) + con.set_trace_callback(trace) + con.execute("create table foo(a, b)") + self.assertTrue(traced_statements) + self.assertTrue(any("create table foo" in stmt for stmt in traced_statements)) + + def CheckClearTraceCallback(self): + """ + Test that setting the trace callback to None clears the previously set callback. + """ + con = sqlite.connect(":memory:") + traced_statements = [] + def trace(statement): + traced_statements.append(statement) + con.set_trace_callback(trace) + con.set_trace_callback(None) + con.execute("create table foo(a, b)") + self.assertFalse(traced_statements, "trace callback was not cleared") + + def CheckUnicodeContent(self): + """ + Test that the statement can contain unicode literals. + """ + unicode_value = '\xf6\xe4\xfc\xd6\xc4\xdc\xdf\u20ac' + con = sqlite.connect(":memory:") + traced_statements = [] + def trace(statement): + traced_statements.append(statement) + con.set_trace_callback(trace) + con.execute("create table foo(x)") + con.execute("insert into foo(x) values (?)", (unicode_value,)) + con.commit() + self.assertTrue(any(unicode_value in stmt for stmt in traced_statements), + "Unicode data garbled in trace callback") + + + def suite(): collation_suite = unittest.makeSuite(CollationTests, "Check") progress_suite = unittest.makeSuite(ProgressTests, "Check") - return unittest.TestSuite((collation_suite, progress_suite)) + trace_suite = unittest.makeSuite(TraceCallbackTests, "Check") + return unittest.TestSuite((collation_suite, progress_suite, trace_suite)) def test(): runner = unittest.TextTestRunner() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -87,6 +87,9 @@ Library ------- +- Issue #11688: Add sqlite3.Connection.set_trace_callback(). Patch by + Torsten Landschoff. + - Issue #11746: Fix SSLContext.load_cert_chain() to accept elliptic curve private keys. diff --git a/Modules/_sqlite/connection.c b/Modules/_sqlite/connection.c --- a/Modules/_sqlite/connection.c +++ b/Modules/_sqlite/connection.c @@ -904,6 +904,38 @@ return rc; } +static void _trace_callback(void* user_arg, const char* statement_string) +{ + PyObject *py_statement = NULL; + PyObject *ret = NULL; + +#ifdef WITH_THREAD + PyGILState_STATE gilstate; + + gilstate = PyGILState_Ensure(); +#endif + py_statement = PyUnicode_DecodeUTF8(statement_string, + strlen(statement_string), "replace"); + if (py_statement) { + ret = PyObject_CallFunctionObjArgs((PyObject*)user_arg, py_statement, NULL); + Py_DECREF(py_statement); + } + + if (ret) { + Py_DECREF(ret); + } else { + if (_enable_callback_tracebacks) { + PyErr_Print(); + } else { + PyErr_Clear(); + } + } + +#ifdef WITH_THREAD + PyGILState_Release(gilstate); +#endif +} + static PyObject* pysqlite_connection_set_authorizer(pysqlite_Connection* self, PyObject* args, PyObject* kwargs) { PyObject* authorizer_cb; @@ -963,6 +995,34 @@ return Py_None; } +static PyObject* pysqlite_connection_set_trace_callback(pysqlite_Connection* self, PyObject* args, PyObject* kwargs) +{ + PyObject* trace_callback; + + static char *kwlist[] = { "trace_callback", NULL }; + + if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) { + return NULL; + } + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O:set_trace_callback", + kwlist, &trace_callback)) { + return NULL; + } + + if (trace_callback == Py_None) { + /* None clears the trace callback previously set */ + sqlite3_trace(self->db, 0, (void*)0); + } else { + if (PyDict_SetItem(self->function_pinboard, trace_callback, Py_None) == -1) + return NULL; + sqlite3_trace(self->db, _trace_callback, trace_callback); + } + + Py_INCREF(Py_None); + return Py_None; +} + #ifdef HAVE_LOAD_EXTENSION static PyObject* pysqlite_enable_load_extension(pysqlite_Connection* self, PyObject* args) { @@ -1516,6 +1576,8 @@ #endif {"set_progress_handler", (PyCFunction)pysqlite_connection_set_progress_handler, METH_VARARGS|METH_KEYWORDS, PyDoc_STR("Sets progress handler callback. Non-standard.")}, + {"set_trace_callback", (PyCFunction)pysqlite_connection_set_trace_callback, METH_VARARGS|METH_KEYWORDS, + PyDoc_STR("Sets a trace callback called for each SQL statement (passed as unicode). Non-standard.")}, {"execute", (PyCFunction)pysqlite_connection_execute, METH_VARARGS, PyDoc_STR("Executes a SQL statement. Non-standard.")}, {"executemany", (PyCFunction)pysqlite_connection_executemany, METH_VARARGS, -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 4 00:50:05 2011 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 04 Apr 2011 00:50:05 +0200 Subject: [Python-checkins] cpython: Improve error message in test Message-ID: http://hg.python.org/cpython/rev/23519bc7d752 changeset: 69121:23519bc7d752 user: Antoine Pitrou date: Mon Apr 04 00:50:01 2011 +0200 summary: Improve error message in test files: Lib/sqlite3/test/hooks.py | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Lib/sqlite3/test/hooks.py b/Lib/sqlite3/test/hooks.py --- a/Lib/sqlite3/test/hooks.py +++ b/Lib/sqlite3/test/hooks.py @@ -216,7 +216,8 @@ con.execute("insert into foo(x) values (?)", (unicode_value,)) con.commit() self.assertTrue(any(unicode_value in stmt for stmt in traced_statements), - "Unicode data garbled in trace callback") + "Unicode data %s garbled in trace callback: %s" + % (ascii(unicode_value), ', '.join(map(ascii, traced_statements)))) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 4 01:22:34 2011 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 04 Apr 2011 01:22:34 +0200 Subject: [Python-checkins] cpython (3.2): Issue #11749: try to fix transient test_socket failure Message-ID: http://hg.python.org/cpython/rev/68a319ef70fc changeset: 69122:68a319ef70fc branch: 3.2 parent: 69114:88ed3de28520 user: Antoine Pitrou date: Mon Apr 04 01:21:37 2011 +0200 summary: Issue #11749: try to fix transient test_socket failure files: Lib/test/test_socket.py | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -1384,6 +1384,10 @@ self.evt1.set() self.evt2.wait(1.0) first_seg = self.read_file.read(len(self.read_msg) - 3) + if first_seg is None: + # Data not arrived (can happen under Windows), wait a bit + time.sleep(0.5) + first_seg = self.read_file.read(len(self.read_msg) - 3) buf = bytearray(10) n = self.read_file.readinto(buf) self.assertEqual(n, 3) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 4 01:22:35 2011 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 04 Apr 2011 01:22:35 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Issue #11749: try to fix transient test_socket failure Message-ID: http://hg.python.org/cpython/rev/44fc5f94bc90 changeset: 69123:44fc5f94bc90 parent: 69121:23519bc7d752 parent: 69122:68a319ef70fc user: Antoine Pitrou date: Mon Apr 04 01:22:06 2011 +0200 summary: Issue #11749: try to fix transient test_socket failure files: Lib/test/test_socket.py | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -1411,6 +1411,10 @@ self.evt1.set() self.evt2.wait(1.0) first_seg = self.read_file.read(len(self.read_msg) - 3) + if first_seg is None: + # Data not arrived (can happen under Windows), wait a bit + time.sleep(0.5) + first_seg = self.read_file.read(len(self.read_msg) - 3) buf = bytearray(10) n = self.read_file.readinto(buf) self.assertEqual(n, 3) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 4 01:50:56 2011 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 04 Apr 2011 01:50:56 +0200 Subject: [Python-checkins] cpython: Fix TraceCallbackTests to not use bound parameters (followup to issue #11688) Message-ID: http://hg.python.org/cpython/rev/ce37570768f5 changeset: 69124:ce37570768f5 user: Antoine Pitrou date: Mon Apr 04 01:50:50 2011 +0200 summary: Fix TraceCallbackTests to not use bound parameters (followup to issue #11688) files: Lib/sqlite3/test/hooks.py | 5 ++++- 1 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Lib/sqlite3/test/hooks.py b/Lib/sqlite3/test/hooks.py --- a/Lib/sqlite3/test/hooks.py +++ b/Lib/sqlite3/test/hooks.py @@ -213,7 +213,10 @@ traced_statements.append(statement) con.set_trace_callback(trace) con.execute("create table foo(x)") - con.execute("insert into foo(x) values (?)", (unicode_value,)) + # Can't execute bound parameters as their values don't appear + # in traced statements before SQLite 3.6.21 + # (cf. http://www.sqlite.org/draft/releaselog/3_6_21.html) + con.execute('insert into foo(x) values ("%s")' % unicode_value) con.commit() self.assertTrue(any(unicode_value in stmt for stmt in traced_statements), "Unicode data %s garbled in trace callback: %s" -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 4 02:14:42 2011 From: python-checkins at python.org (steven.bethard) Date: Mon, 04 Apr 2011 02:14:42 +0200 Subject: [Python-checkins] cpython (2.7): Issue #9347: Fix formatting for tuples in argparse type= error messages. Message-ID: http://hg.python.org/cpython/rev/f961e9179998 changeset: 69125:f961e9179998 branch: 2.7 parent: 69080:5e7fc2a42c3c user: Steven Bethard date: Mon Apr 04 01:47:52 2011 +0200 summary: Issue #9347: Fix formatting for tuples in argparse type= error messages. files: Lib/argparse.py | 4 ++-- Lib/test/test_argparse.py | 2 ++ Misc/NEWS | 2 ++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Lib/argparse.py b/Lib/argparse.py --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -1277,13 +1277,13 @@ # create the action object, and add it to the parser action_class = self._pop_action_class(kwargs) if not _callable(action_class): - raise ValueError('unknown action "%s"' % action_class) + raise ValueError('unknown action "%s"' % (action_class,)) action = action_class(**kwargs) # raise an error if the action type is not callable type_func = self._registry_get('type', action.type, action.type) if not _callable(type_func): - raise ValueError('%r is not callable' % type_func) + raise ValueError('%r is not callable' % (type_func,)) # raise an error if the metavar does not match the type if hasattr(self, "_get_formatter"): diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -4016,10 +4016,12 @@ def test_invalid_type(self): self.assertValueError('--foo', type='int') + self.assertValueError('--foo', type=(int, float)) def test_invalid_action(self): self.assertValueError('-x', action='foo') self.assertValueError('foo', action='baz') + self.assertValueError('--foo', action=('store', 'append')) parser = argparse.ArgumentParser() try: parser.add_argument("--foo", action="store-true") diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -257,6 +257,8 @@ - Issue #9026: Fix order of argparse sub-commands in help messages. +- Issue #9347: Fix formatting for tuples in argparse type= error messages. + Extension Modules ----------------- -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 4 02:14:43 2011 From: python-checkins at python.org (steven.bethard) Date: Mon, 04 Apr 2011 02:14:43 +0200 Subject: [Python-checkins] cpython (3.2): Issue #9347: Fix formatting for tuples in argparse type= error messages. Message-ID: http://hg.python.org/cpython/rev/69ab5251f3f0 changeset: 69126:69ab5251f3f0 branch: 3.2 parent: 69122:68a319ef70fc user: Steven Bethard date: Mon Apr 04 01:53:02 2011 +0200 summary: Issue #9347: Fix formatting for tuples in argparse type= error messages. files: Lib/argparse.py | 4 ++-- Lib/test/test_argparse.py | 2 ++ Misc/NEWS | 2 ++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Lib/argparse.py b/Lib/argparse.py --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -1287,13 +1287,13 @@ # create the action object, and add it to the parser action_class = self._pop_action_class(kwargs) if not _callable(action_class): - raise ValueError('unknown action "%s"' % action_class) + raise ValueError('unknown action "%s"' % (action_class,)) action = action_class(**kwargs) # raise an error if the action type is not callable type_func = self._registry_get('type', action.type, action.type) if not _callable(type_func): - raise ValueError('%r is not callable' % type_func) + raise ValueError('%r is not callable' % (type_func,)) # raise an error if the metavar does not match the type if hasattr(self, "_get_formatter"): diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -4051,10 +4051,12 @@ def test_invalid_type(self): self.assertValueError('--foo', type='int') + self.assertValueError('--foo', type=(int, float)) def test_invalid_action(self): self.assertValueError('-x', action='foo') self.assertValueError('foo', action='baz') + self.assertValueError('--foo', action=('store', 'append')) parser = argparse.ArgumentParser() try: parser.add_argument("--foo", action="store-true") diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -188,6 +188,8 @@ - Issue #9026: Fix order of argparse sub-commands in help messages. +- Issue #9347: Fix formatting for tuples in argparse type= error messages. + Build ----- -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 4 02:14:46 2011 From: python-checkins at python.org (steven.bethard) Date: Mon, 04 Apr 2011 02:14:46 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Issue #9347: Fix formatting for tuples in argparse type= error messages. Message-ID: http://hg.python.org/cpython/rev/1f3f6443810a changeset: 69127:1f3f6443810a parent: 69123:44fc5f94bc90 parent: 69126:69ab5251f3f0 user: Steven Bethard date: Mon Apr 04 02:10:40 2011 +0200 summary: Issue #9347: Fix formatting for tuples in argparse type= error messages. files: Lib/argparse.py | 4 ++-- Lib/test/test_argparse.py | 2 ++ Misc/NEWS | 2 ++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Lib/argparse.py b/Lib/argparse.py --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -1312,13 +1312,13 @@ # create the action object, and add it to the parser action_class = self._pop_action_class(kwargs) if not _callable(action_class): - raise ValueError('unknown action "%s"' % action_class) + raise ValueError('unknown action "%s"' % (action_class,)) action = action_class(**kwargs) # raise an error if the action type is not callable type_func = self._registry_get('type', action.type, action.type) if not _callable(type_func): - raise ValueError('%r is not callable' % type_func) + raise ValueError('%r is not callable' % (type_func,)) # raise an error if the metavar does not match the type if hasattr(self, "_get_formatter"): diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -4082,10 +4082,12 @@ def test_invalid_type(self): self.assertValueError('--foo', type='int') + self.assertValueError('--foo', type=(int, float)) def test_invalid_action(self): self.assertValueError('-x', action='foo') self.assertValueError('foo', action='baz') + self.assertValueError('--foo', action=('store', 'append')) parser = argparse.ArgumentParser() try: parser.add_argument("--foo", action="store-true") diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -349,6 +349,8 @@ - Issue #9026: Fix order of argparse sub-commands in help messages. +- Issue #9347: Fix formatting for tuples in argparse type= error messages. + Build ----- -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 4 02:14:48 2011 From: python-checkins at python.org (steven.bethard) Date: Mon, 04 Apr 2011 02:14:48 +0200 Subject: [Python-checkins] cpython (merge default -> default): Merge Message-ID: http://hg.python.org/cpython/rev/838e3b07a7f8 changeset: 69128:838e3b07a7f8 parent: 69127:1f3f6443810a parent: 69124:ce37570768f5 user: Steven Bethard date: Mon Apr 04 02:14:25 2011 +0200 summary: Merge files: Lib/sqlite3/test/hooks.py | 5 ++++- 1 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Lib/sqlite3/test/hooks.py b/Lib/sqlite3/test/hooks.py --- a/Lib/sqlite3/test/hooks.py +++ b/Lib/sqlite3/test/hooks.py @@ -213,7 +213,10 @@ traced_statements.append(statement) con.set_trace_callback(trace) con.execute("create table foo(x)") - con.execute("insert into foo(x) values (?)", (unicode_value,)) + # Can't execute bound parameters as their values don't appear + # in traced statements before SQLite 3.6.21 + # (cf. http://www.sqlite.org/draft/releaselog/3_6_21.html) + con.execute('insert into foo(x) values ("%s")' % unicode_value) con.commit() self.assertTrue(any(unicode_value in stmt for stmt in traced_statements), "Unicode data %s garbled in trace callback: %s" -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Mon Apr 4 04:55:49 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Mon, 04 Apr 2011 04:55:49 +0200 Subject: [Python-checkins] Daily reference leaks (838e3b07a7f8): sum=0 Message-ID: results for 838e3b07a7f8 on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogYOwho_', '-x'] From python-checkins at python.org Mon Apr 4 11:05:51 2011 From: python-checkins at python.org (victor.stinner) Date: Mon, 04 Apr 2011 11:05:51 +0200 Subject: [Python-checkins] cpython: Issue #11753: faulthandler thread uses pthread_sigmask() Message-ID: http://hg.python.org/cpython/rev/ebc03d7e7110 changeset: 69129:ebc03d7e7110 user: Victor Stinner date: Mon Apr 04 11:05:21 2011 +0200 summary: Issue #11753: faulthandler thread uses pthread_sigmask() The thread must not receive any signal. If the thread receives a signal, sem_timedwait() is interrupted and returns EINTR, but in this case, PyThread_acquire_lock_timed() retries sem_timedwait() and the main thread is not aware of the signal. The problem is that some tests expect that the main thread receives the signal, not faulthandler handler, which should be invisible. On Linux, the signal looks to be received by the main thread, whereas on FreeBSD, it can be any thread. files: Modules/faulthandler.c | 11 +++++++++++ 1 files changed, 11 insertions(+), 0 deletions(-) diff --git a/Modules/faulthandler.c b/Modules/faulthandler.c --- a/Modules/faulthandler.c +++ b/Modules/faulthandler.c @@ -399,6 +399,17 @@ const char* errmsg; PyThreadState *current; int ok; +#ifdef HAVE_PTHREAD_H + sigset_t set; + + /* we don't want to receive any signal */ + sigfillset(&set); +#if defined(HAVE_PTHREAD_SIGMASK) && !defined(HAVE_BROKEN_PTHREAD_SIGMASK) + pthread_sigmask(SIG_SETMASK, &set, NULL); +#else + sigprocmask(SIG_SETMASK, &set, NULL); +#endif +#endif do { st = PyThread_acquire_lock_timed(thread.cancel_event, -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 4 12:54:47 2011 From: python-checkins at python.org (victor.stinner) Date: Mon, 04 Apr 2011 12:54:47 +0200 Subject: [Python-checkins] cpython: Reenable regrtest.py timeout (30 min): #11738 and #11753 looks to be fixed Message-ID: http://hg.python.org/cpython/rev/9d59ae98013c changeset: 69130:9d59ae98013c user: Victor Stinner date: Mon Apr 04 12:54:33 2011 +0200 summary: Reenable regrtest.py timeout (30 min): #11738 and #11753 looks to be fixed files: Lib/test/regrtest.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -240,7 +240,7 @@ findleaks=False, use_resources=None, trace=False, coverdir='coverage', runleaks=False, huntrleaks=False, verbose2=False, print_slow=False, random_seed=None, use_mp=None, verbose3=False, forever=False, - header=False, timeout=None): + header=False, timeout=30*60): """Execute a test suite. This also parses command-line options and modifies its behavior -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 4 15:33:37 2011 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 04 Apr 2011 15:33:37 +0200 Subject: [Python-checkins] peps: Fix use of "either" and typo in "checking" (Jim Jewett) Message-ID: http://hg.python.org/peps/rev/f65beac56930 changeset: 3854:f65beac56930 user: Antoine Pitrou date: Mon Apr 04 15:33:34 2011 +0200 summary: Fix use of "either" and typo in "checking" (Jim Jewett) files: pep-3151.txt | 18 +++++++++--------- 1 files changed, 9 insertions(+), 9 deletions(-) diff --git a/pep-3151.txt b/pep-3151.txt --- a/pep-3151.txt +++ b/pep-3151.txt @@ -83,12 +83,12 @@ A further proof of the ambiguity of this segmentation is that the standard library itself sometimes has problems deciding. For example, in the -``select`` module, similar failures will raise either ``select.error``, -``OSError`` or ``IOError`` depending on whether you are using select(), -a poll object, a kqueue object, or an epoll object. This makes user code -uselessly complicated since it has to be prepared to catch various -exception types, depending on which exact implementation of a single -primitive it chooses to use at runtime. +``select`` module, similar failures will raise ``select.error``, ``OSError`` +or ``IOError`` depending on whether you are using select(), a poll object, +a kqueue object, or an epoll object. This makes user code uselessly +complicated since it has to be prepared to catch various exception types, +depending on which exact implementation of a single primitive it chooses +to use at runtime. As for WindowsError, it seems to be a pointless distinction. First, it only exists on Windows systems, which requires tedious compatibility code @@ -171,10 +171,10 @@ For this we first must explain what we will call *careful* and *careless* exception handling. *Careless* (or "na?ve") code is defined as code which -blindly catches either of ``OSError``, ``IOError``, ``socket.error``, -``mmap.error``, ``WindowsError``, ``select.error`` without cheking the ``errno`` +blindly catches any of ``OSError``, ``IOError``, ``socket.error``, +``mmap.error``, ``WindowsError``, ``select.error`` without checking the ``errno`` attribute. This is because such exception types are much too broad to signify -anything. Either of them can be raised for error conditions as diverse as: a +anything. Any of them can be raised for error conditions as diverse as: a bad file descriptor (which will usually indicate a programming error), an unconnected socket (ditto), a socket timeout, a file type mismatch, an invalid argument, a transmission failure, insufficient permissions, a non-existent -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Mon Apr 4 18:30:23 2011 From: python-checkins at python.org (raymond.hettinger) Date: Mon, 04 Apr 2011 18:30:23 +0200 Subject: [Python-checkins] cpython: Update timeit to use the new string formatting syntax. Message-ID: http://hg.python.org/cpython/rev/81c981ceb83e changeset: 69131:81c981ceb83e user: Raymond Hettinger date: Mon Apr 04 09:28:25 2011 -0700 summary: Update timeit to use the new string formatting syntax. files: Lib/timeit.py | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Lib/timeit.py b/Lib/timeit.py --- a/Lib/timeit.py +++ b/Lib/timeit.py @@ -79,10 +79,10 @@ # being indented 8 spaces. template = """ def inner(_it, _timer): - %(setup)s + {setup} _t0 = _timer() for _i in _it: - %(stmt)s + {stmt} _t1 = _timer() return _t1 - _t0 """ @@ -126,9 +126,9 @@ stmt = reindent(stmt, 8) if isinstance(setup, str): setup = reindent(setup, 4) - src = template % {'stmt': stmt, 'setup': setup} + src = template.format(stmt=stmt, setup=setup) elif hasattr(setup, '__call__'): - src = template % {'stmt': stmt, 'setup': '_setup()'} + src = template.format(stmt=stmt, setup='_setup()') ns['_setup'] = setup else: raise ValueError("setup is neither a string nor callable") -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 4 19:53:20 2011 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 04 Apr 2011 19:53:20 +0200 Subject: [Python-checkins] cpython (3.1): Issue #11761: make tests for gc.get_count() less fragile Message-ID: http://hg.python.org/cpython/rev/36d92e923a1a changeset: 69132:36d92e923a1a branch: 3.1 parent: 69106:821244a44163 user: Antoine Pitrou date: Mon Apr 04 19:50:42 2011 +0200 summary: Issue #11761: make tests for gc.get_count() less fragile files: Lib/test/test_gc.py | 43 ++++++++++++++++++++------------ 1 files changed, 27 insertions(+), 16 deletions(-) diff --git a/Lib/test/test_gc.py b/Lib/test/test_gc.py --- a/Lib/test/test_gc.py +++ b/Lib/test/test_gc.py @@ -239,30 +239,41 @@ # The following two tests are fragile: # They precisely count the number of allocations, # which is highly implementation-dependent. - # For example: - # - disposed tuples are not freed, but reused - # - the call to assertEqual somehow avoids building its args tuple + # For example, disposed tuples are not freed, but reused. + # To minimize variations, though, we first store the get_count() results + # and check them at the end. def test_get_count(self): - # Avoid future allocation of method object - assertEqual = self._baseAssertEqual gc.collect() - assertEqual(gc.get_count(), (0, 0, 0)) - a = dict() - # since gc.collect(), we created two objects: - # the dict, and the tuple returned by get_count() - assertEqual(gc.get_count(), (2, 0, 0)) + a, b, c = gc.get_count() + x = [] + d, e, f = gc.get_count() + self.assertEqual((b, c), (0, 0)) + self.assertEqual((e, f), (0, 0)) + # This is less fragile than asserting that a equals 0. + self.assertLess(a, 5) + # Between the two calls to get_count(), at least one object was + # created (the list). + self.assertGreater(d, a) def test_collect_generations(self): - # Avoid future allocation of method object - assertEqual = self.assertEqual gc.collect() - a = dict() + # This object will "trickle" into generation N + 1 after + # each call to collect(N) + x = [] gc.collect(0) - assertEqual(gc.get_count(), (0, 1, 0)) + # x is now in gen 1 + a, b, c = gc.get_count() gc.collect(1) - assertEqual(gc.get_count(), (0, 0, 1)) + # x is now in gen 2 + d, e, f = gc.get_count() gc.collect(2) - assertEqual(gc.get_count(), (0, 0, 0)) + # x is now in gen 3 + g, h, i = gc.get_count() + # We don't check a, d, g since their exact values depends on + # internal implementation details of the interpreter. + self.assertEqual((b, c), (1, 0)) + self.assertEqual((e, f), (0, 1)) + self.assertEqual((h, i), (0, 0)) def test_trashcan(self): class Ouch: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 4 19:53:21 2011 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 04 Apr 2011 19:53:21 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): Issue #11761: make tests for gc.get_count() less fragile Message-ID: http://hg.python.org/cpython/rev/5daf9a8dc4e8 changeset: 69133:5daf9a8dc4e8 branch: 3.2 parent: 69126:69ab5251f3f0 parent: 69132:36d92e923a1a user: Antoine Pitrou date: Mon Apr 04 19:51:33 2011 +0200 summary: Issue #11761: make tests for gc.get_count() less fragile files: Lib/test/test_gc.py | 43 ++++++++++++++++++++------------ 1 files changed, 27 insertions(+), 16 deletions(-) diff --git a/Lib/test/test_gc.py b/Lib/test/test_gc.py --- a/Lib/test/test_gc.py +++ b/Lib/test/test_gc.py @@ -239,30 +239,41 @@ # The following two tests are fragile: # They precisely count the number of allocations, # which is highly implementation-dependent. - # For example: - # - disposed tuples are not freed, but reused - # - the call to assertEqual somehow avoids building its args tuple + # For example, disposed tuples are not freed, but reused. + # To minimize variations, though, we first store the get_count() results + # and check them at the end. def test_get_count(self): - # Avoid future allocation of method object - assertEqual = self._baseAssertEqual gc.collect() - assertEqual(gc.get_count(), (0, 0, 0)) - a = dict() - # since gc.collect(), we created two objects: - # the dict, and the tuple returned by get_count() - assertEqual(gc.get_count(), (2, 0, 0)) + a, b, c = gc.get_count() + x = [] + d, e, f = gc.get_count() + self.assertEqual((b, c), (0, 0)) + self.assertEqual((e, f), (0, 0)) + # This is less fragile than asserting that a equals 0. + self.assertLess(a, 5) + # Between the two calls to get_count(), at least one object was + # created (the list). + self.assertGreater(d, a) def test_collect_generations(self): - # Avoid future allocation of method object - assertEqual = self.assertEqual gc.collect() - a = dict() + # This object will "trickle" into generation N + 1 after + # each call to collect(N) + x = [] gc.collect(0) - assertEqual(gc.get_count(), (0, 1, 0)) + # x is now in gen 1 + a, b, c = gc.get_count() gc.collect(1) - assertEqual(gc.get_count(), (0, 0, 1)) + # x is now in gen 2 + d, e, f = gc.get_count() gc.collect(2) - assertEqual(gc.get_count(), (0, 0, 0)) + # x is now in gen 3 + g, h, i = gc.get_count() + # We don't check a, d, g since their exact values depends on + # internal implementation details of the interpreter. + self.assertEqual((b, c), (1, 0)) + self.assertEqual((e, f), (0, 1)) + self.assertEqual((h, i), (0, 0)) def test_trashcan(self): class Ouch: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 4 19:53:23 2011 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 04 Apr 2011 19:53:23 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Issue #11761: make tests for gc.get_count() less fragile Message-ID: http://hg.python.org/cpython/rev/24d4c5fd3bc6 changeset: 69134:24d4c5fd3bc6 parent: 69131:81c981ceb83e parent: 69133:5daf9a8dc4e8 user: Antoine Pitrou date: Mon Apr 04 19:52:56 2011 +0200 summary: Issue #11761: make tests for gc.get_count() less fragile files: Lib/test/test_gc.py | 43 ++++++++++++++++++++------------ 1 files changed, 27 insertions(+), 16 deletions(-) diff --git a/Lib/test/test_gc.py b/Lib/test/test_gc.py --- a/Lib/test/test_gc.py +++ b/Lib/test/test_gc.py @@ -241,32 +241,43 @@ # The following two tests are fragile: # They precisely count the number of allocations, # which is highly implementation-dependent. - # For example: - # - disposed tuples are not freed, but reused - # - the call to assertEqual somehow avoids building its args tuple + # For example, disposed tuples are not freed, but reused. + # To minimize variations, though, we first store the get_count() results + # and check them at the end. @refcount_test def test_get_count(self): - # Avoid future allocation of method object - assertEqual = self._baseAssertEqual gc.collect() - assertEqual(gc.get_count(), (0, 0, 0)) - a = dict() - # since gc.collect(), we created two objects: - # the dict, and the tuple returned by get_count() - assertEqual(gc.get_count(), (2, 0, 0)) + a, b, c = gc.get_count() + x = [] + d, e, f = gc.get_count() + self.assertEqual((b, c), (0, 0)) + self.assertEqual((e, f), (0, 0)) + # This is less fragile than asserting that a equals 0. + self.assertLess(a, 5) + # Between the two calls to get_count(), at least one object was + # created (the list). + self.assertGreater(d, a) @refcount_test def test_collect_generations(self): - # Avoid future allocation of method object - assertEqual = self.assertEqual gc.collect() - a = dict() + # This object will "trickle" into generation N + 1 after + # each call to collect(N) + x = [] gc.collect(0) - assertEqual(gc.get_count(), (0, 1, 0)) + # x is now in gen 1 + a, b, c = gc.get_count() gc.collect(1) - assertEqual(gc.get_count(), (0, 0, 1)) + # x is now in gen 2 + d, e, f = gc.get_count() gc.collect(2) - assertEqual(gc.get_count(), (0, 0, 0)) + # x is now in gen 3 + g, h, i = gc.get_count() + # We don't check a, d, g since their exact values depends on + # internal implementation details of the interpreter. + self.assertEqual((b, c), (1, 0)) + self.assertEqual((e, f), (0, 1)) + self.assertEqual((h, i), (0, 0)) def test_trashcan(self): class Ouch: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 4 20:00:56 2011 From: python-checkins at python.org (brian.curtin) Date: Mon, 04 Apr 2011 20:00:56 +0200 Subject: [Python-checkins] cpython: Add x64-temp to ignore, prepend a forward slash to "build/" to include Message-ID: http://hg.python.org/cpython/rev/4d2575d971bc changeset: 69135:4d2575d971bc user: brian.curtin date: Mon Apr 04 13:00:49 2011 -0500 summary: Add x64-temp to ignore, prepend a forward slash to "build/" to include PCbuild/ changes (for VS project files, etc). files: .hgignore | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/.hgignore b/.hgignore --- a/.hgignore +++ b/.hgignore @@ -5,7 +5,7 @@ Makefile.pre$ TAGS$ autom4te.cache$ -build/ +/build/ buildno$ config.cache config.log @@ -63,4 +63,5 @@ PCbuild/*.ncb PCbuild/*.bsc PCbuild/Win32-temp-* +PCbuild/x64-temp-* __pycache__ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 4 20:56:06 2011 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 04 Apr 2011 20:56:06 +0200 Subject: [Python-checkins] cpython: Ignore build/ and Doc/build Message-ID: http://hg.python.org/cpython/rev/739bed65e445 changeset: 69136:739bed65e445 user: Antoine Pitrou date: Mon Apr 04 20:52:50 2011 +0200 summary: Ignore build/ and Doc/build files: .hgignore | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/.hgignore b/.hgignore --- a/.hgignore +++ b/.hgignore @@ -5,7 +5,8 @@ Makefile.pre$ TAGS$ autom4te.cache$ -/build/ +^build/ +^Doc/build/ buildno$ config.cache config.log -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 4 20:56:09 2011 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 04 Apr 2011 20:56:09 +0200 Subject: [Python-checkins] cpython: Ignore AMD64 build files under Windows Message-ID: http://hg.python.org/cpython/rev/ef97e997aa02 changeset: 69137:ef97e997aa02 user: Antoine Pitrou date: Mon Apr 04 20:55:12 2011 +0200 summary: Ignore AMD64 build files under Windows files: .hgignore | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/.hgignore b/.hgignore --- a/.hgignore +++ b/.hgignore @@ -33,6 +33,7 @@ Modules/ld_so_aix$ Parser/pgen$ Parser/pgen.stamp$ +PCbuild/amd64/ ^core ^python-gdb.py ^python.exe-gdb.py -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 4 20:56:14 2011 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 04 Apr 2011 20:56:14 +0200 Subject: [Python-checkins] cpython: Ignore other MSVC by-products Message-ID: http://hg.python.org/cpython/rev/100561a0f093 changeset: 69138:100561a0f093 user: Antoine Pitrou date: Mon Apr 04 20:55:48 2011 +0200 summary: Ignore other MSVC by-products files: .hgignore | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/.hgignore b/.hgignore --- a/.hgignore +++ b/.hgignore @@ -64,6 +64,8 @@ PCbuild/*.o PCbuild/*.ncb PCbuild/*.bsc +PCbuild/*.user +PCbuild/*.suo PCbuild/Win32-temp-* PCbuild/x64-temp-* __pycache__ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 4 21:01:57 2011 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 04 Apr 2011 21:01:57 +0200 Subject: [Python-checkins] cpython: Issue #10791: Implement missing method GzipFile.read1(), allowing GzipFile Message-ID: http://hg.python.org/cpython/rev/9775d67c9af9 changeset: 69139:9775d67c9af9 user: Antoine Pitrou date: Mon Apr 04 21:00:37 2011 +0200 summary: Issue #10791: Implement missing method GzipFile.read1(), allowing GzipFile to be wrapped in a TextIOWrapper. Patch by Nadeem Vawda. files: Lib/gzip.py | 22 ++++++++++++++++++++++ Lib/test/test_gzip.py | 23 +++++++++++++++++++++++ Misc/NEWS | 3 +++ 3 files changed, 48 insertions(+), 0 deletions(-) diff --git a/Lib/gzip.py b/Lib/gzip.py --- a/Lib/gzip.py +++ b/Lib/gzip.py @@ -348,6 +348,28 @@ self.offset += size return chunk + def read1(self, size=-1): + self._check_closed() + if self.mode != READ: + import errno + raise IOError(errno.EBADF, "read1() on write-only GzipFile object") + + if self.extrasize <= 0 and self.fileobj is None: + return b'' + + try: + self._read() + except EOFError: + pass + if size < 0 or size > self.extrasize: + size = self.extrasize + + offset = self.offset - self.extrastart + chunk = self.extrabuf[offset: offset + size] + self.extrasize -= size + self.offset += size + return chunk + def peek(self, n): if self.mode != READ: import errno diff --git a/Lib/test/test_gzip.py b/Lib/test/test_gzip.py --- a/Lib/test/test_gzip.py +++ b/Lib/test/test_gzip.py @@ -64,6 +64,21 @@ d = f.read() self.assertEqual(d, data1*50) + def test_read1(self): + self.test_write() + blocks = [] + nread = 0 + with gzip.GzipFile(self.filename, 'r') as f: + while True: + d = f.read1() + if not d: + break + blocks.append(d) + nread += len(d) + # Check that position was updated correctly (see issue10791). + self.assertEqual(f.tell(), nread) + self.assertEqual(b''.join(blocks), data1 * 50) + def test_io_on_closed_object(self): # Test that I/O operations on closed GzipFile objects raise a # ValueError, just like the corresponding functions on file objects. @@ -323,6 +338,14 @@ self.assertEqual(f.read(100), b'') self.assertEqual(nread, len(uncompressed)) + def test_textio_readlines(self): + # Issue #10791: TextIOWrapper.readlines() fails when wrapping GzipFile. + lines = (data1 * 50).decode("ascii").splitlines(True) + self.test_write() + with gzip.GzipFile(self.filename, 'r') as f: + with io.TextIOWrapper(f, encoding="ascii") as t: + self.assertEqual(t.readlines(), lines) + # Testing compress/decompress shortcut functions def test_compress(self): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -87,6 +87,9 @@ Library ------- +- Issue #10791: Implement missing method GzipFile.read1(), allowing GzipFile + to be wrapped in a TextIOWrapper. Patch by Nadeem Vawda. + - Issue #11688: Add sqlite3.Connection.set_trace_callback(). Patch by Torsten Landschoff. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 4 21:09:09 2011 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 04 Apr 2011 21:09:09 +0200 Subject: [Python-checkins] cpython (3.2): Clarify that GzipFile.read1() isn't implemented. Message-ID: http://hg.python.org/cpython/rev/8a2639fdf433 changeset: 69140:8a2639fdf433 branch: 3.2 parent: 69133:5daf9a8dc4e8 user: Antoine Pitrou date: Mon Apr 04 21:06:20 2011 +0200 summary: Clarify that GzipFile.read1() isn't implemented. files: Doc/library/gzip.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/gzip.rst b/Doc/library/gzip.rst --- a/Doc/library/gzip.rst +++ b/Doc/library/gzip.rst @@ -72,7 +72,7 @@ :class:`GzipFile` supports the :class:`io.BufferedIOBase` interface, including iteration and the :keyword:`with` statement. Only the - :meth:`truncate` method isn't implemented. + :meth:`read1` and :meth:`truncate` methods aren't implemented. :class:`GzipFile` also provides the following method: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 4 21:09:10 2011 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 04 Apr 2011 21:09:10 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Clarify that GzipFile.read1() is now implemented Message-ID: http://hg.python.org/cpython/rev/4fa9bfa21a7e changeset: 69141:4fa9bfa21a7e parent: 69139:9775d67c9af9 parent: 69140:8a2639fdf433 user: Antoine Pitrou date: Mon Apr 04 21:09:05 2011 +0200 summary: Clarify that GzipFile.read1() is now implemented files: Doc/library/gzip.rst | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/Doc/library/gzip.rst b/Doc/library/gzip.rst --- a/Doc/library/gzip.rst +++ b/Doc/library/gzip.rst @@ -94,6 +94,9 @@ .. versionchanged:: 3.2 Support for unseekable files was added. + .. versionchanged:: 3.3 + The :meth:`io.BufferedIOBase.read1` method is now implemented. + .. function:: open(filename, mode='rb', compresslevel=9) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 4 22:00:51 2011 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 04 Apr 2011 22:00:51 +0200 Subject: [Python-checkins] cpython (3.1): Try to fix sporadic failure in test_thread/test_threading Message-ID: http://hg.python.org/cpython/rev/04b5cd2f8c87 changeset: 69142:04b5cd2f8c87 branch: 3.1 parent: 69132:36d92e923a1a user: Antoine Pitrou date: Mon Apr 04 21:59:09 2011 +0200 summary: Try to fix sporadic failure in test_thread/test_threading files: Lib/test/lock_tests.py | 8 +++++++- 1 files changed, 7 insertions(+), 1 deletions(-) diff --git a/Lib/test/lock_tests.py b/Lib/test/lock_tests.py --- a/Lib/test/lock_tests.py +++ b/Lib/test/lock_tests.py @@ -141,7 +141,13 @@ # We run many threads in the hope that existing threads ids won't # be recycled. Bunch(f, 15).wait_for_finished() - self.assertEqual(n, len(threading.enumerate())) + if len(threading.enumerate()) != n: + # There is a small window during which a Thread instance's + # target function has finished running, but the Thread is still + # alive and registered. Avoid spurious failures by waiting a + # bit more (seen on a buildbot). + time.sleep(0.4) + self.assertEqual(n, len(threading.enumerate())) class LockTests(BaseLockTests): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 4 22:00:52 2011 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 04 Apr 2011 22:00:52 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): Try to fix sporadic failure in test_thread/test_threading Message-ID: http://hg.python.org/cpython/rev/8d5ea25d79d0 changeset: 69143:8d5ea25d79d0 branch: 3.2 parent: 69140:8a2639fdf433 parent: 69142:04b5cd2f8c87 user: Antoine Pitrou date: Mon Apr 04 22:00:10 2011 +0200 summary: Try to fix sporadic failure in test_thread/test_threading files: Lib/test/lock_tests.py | 8 +++++++- 1 files changed, 7 insertions(+), 1 deletions(-) diff --git a/Lib/test/lock_tests.py b/Lib/test/lock_tests.py --- a/Lib/test/lock_tests.py +++ b/Lib/test/lock_tests.py @@ -149,7 +149,13 @@ # We run many threads in the hope that existing threads ids won't # be recycled. Bunch(f, 15).wait_for_finished() - self.assertEqual(n, len(threading.enumerate())) + if len(threading.enumerate()) != n: + # There is a small window during which a Thread instance's + # target function has finished running, but the Thread is still + # alive and registered. Avoid spurious failures by waiting a + # bit more (seen on a buildbot). + time.sleep(0.4) + self.assertEqual(n, len(threading.enumerate())) def test_timeout(self): lock = self.locktype() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 4 22:00:58 2011 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 04 Apr 2011 22:00:58 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Try to fix sporadic failure in test_thread/test_threading Message-ID: http://hg.python.org/cpython/rev/877e152c2eee changeset: 69144:877e152c2eee parent: 69141:4fa9bfa21a7e parent: 69143:8d5ea25d79d0 user: Antoine Pitrou date: Mon Apr 04 22:00:45 2011 +0200 summary: Try to fix sporadic failure in test_thread/test_threading files: Lib/test/lock_tests.py | 8 +++++++- 1 files changed, 7 insertions(+), 1 deletions(-) diff --git a/Lib/test/lock_tests.py b/Lib/test/lock_tests.py --- a/Lib/test/lock_tests.py +++ b/Lib/test/lock_tests.py @@ -149,7 +149,13 @@ # We run many threads in the hope that existing threads ids won't # be recycled. Bunch(f, 15).wait_for_finished() - self.assertEqual(n, len(threading.enumerate())) + if len(threading.enumerate()) != n: + # There is a small window during which a Thread instance's + # target function has finished running, but the Thread is still + # alive and registered. Avoid spurious failures by waiting a + # bit more (seen on a buildbot). + time.sleep(0.4) + self.assertEqual(n, len(threading.enumerate())) def test_timeout(self): lock = self.locktype() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 4 23:13:51 2011 From: python-checkins at python.org (victor.stinner) Date: Mon, 04 Apr 2011 23:13:51 +0200 Subject: [Python-checkins] cpython: Issue #11619: _PyImport_LoadDynamicModule() doesn't encode the path to bytes Message-ID: http://hg.python.org/cpython/rev/1b7f484bab6e changeset: 69145:1b7f484bab6e user: Victor Stinner date: Mon Apr 04 23:05:53 2011 +0200 summary: Issue #11619: _PyImport_LoadDynamicModule() doesn't encode the path to bytes on Windows. files: Misc/NEWS | 3 ++ Python/dynload_win.c | 33 +++++++++++++++---------------- Python/importdl.c | 11 ++++++++++ 3 files changed, 30 insertions(+), 17 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #11619: _PyImport_LoadDynamicModule() doesn't encode the path to bytes + on Windows. + - Issue #10998: Remove mentions of -Q, sys.flags.division_warning and Py_DivisionWarningFlag left over from Python 2. diff --git a/Python/dynload_win.c b/Python/dynload_win.c --- a/Python/dynload_win.c +++ b/Python/dynload_win.c @@ -171,8 +171,8 @@ return NULL; } -dl_funcptr _PyImport_GetDynLoadFunc(const char *shortname, - const char *pathname, FILE *fp) +dl_funcptr _PyImport_GetDynLoadWindows(const char *shortname, + PyObject *pathname, FILE *fp) { dl_funcptr p; char funcname[258], *import_python; @@ -185,8 +185,7 @@ { HINSTANCE hDLL = NULL; - char pathbuf[260]; - LPTSTR dummy; + wchar_t pathbuf[260]; unsigned int old_mode; ULONG_PTR cookie = 0; /* We use LoadLibraryEx so Windows looks for dependent DLLs @@ -198,14 +197,14 @@ /* Don't display a message box when Python can't load a DLL */ old_mode = SetErrorMode(SEM_FAILCRITICALERRORS); - if (GetFullPathName(pathname, - sizeof(pathbuf), - pathbuf, - &dummy)) { + if (GetFullPathNameW(PyUnicode_AS_UNICODE(pathname), + sizeof(pathbuf) / sizeof(pathbuf[0]), + pathbuf, + NULL)) { ULONG_PTR cookie = _Py_ActivateActCtx(); /* XXX This call doesn't exist in Windows CE */ - hDLL = LoadLibraryEx(pathname, NULL, - LOAD_WITH_ALTERED_SEARCH_PATH); + hDLL = LoadLibraryExW(PyUnicode_AS_UNICODE(pathname), NULL, + LOAD_WITH_ALTERED_SEARCH_PATH); _Py_DeactivateActCtx(cookie); } @@ -264,21 +263,21 @@ } else { char buffer[256]; + PyOS_snprintf(buffer, sizeof(buffer), #ifdef _DEBUG - PyOS_snprintf(buffer, sizeof(buffer), "python%d%d_d.dll", + "python%d%d_d.dll", #else - PyOS_snprintf(buffer, sizeof(buffer), "python%d%d.dll", + "python%d%d.dll", #endif PY_MAJOR_VERSION,PY_MINOR_VERSION); import_python = GetPythonImport(hDLL); if (import_python && strcasecmp(buffer,import_python)) { - PyOS_snprintf(buffer, sizeof(buffer), - "Module use of %.150s conflicts " - "with this version of Python.", - import_python); - PyErr_SetString(PyExc_ImportError,buffer); + PyErr_Format(PyExc_ImportError, + "Module use of %.150s conflicts " + "with this version of Python.", + import_python); FreeLibrary(hDLL); return NULL; } diff --git a/Python/importdl.c b/Python/importdl.c --- a/Python/importdl.c +++ b/Python/importdl.c @@ -12,8 +12,13 @@ #include "importdl.h" +#ifdef MS_WINDOWS +extern dl_funcptr _PyImport_GetDynLoadWindows(const char *shortname, + PyObject *pathname, FILE *fp); +#else extern dl_funcptr _PyImport_GetDynLoadFunc(const char *shortname, const char *pathname, FILE *fp); +#endif /* name should be ASCII only because the C language doesn't accept non-ASCII identifiers, and dynamic modules are written in C. */ @@ -22,7 +27,9 @@ _PyImport_LoadDynamicModule(PyObject *name, PyObject *path, FILE *fp) { PyObject *m; +#ifndef MS_WINDOWS PyObject *pathbytes; +#endif char *namestr, *lastdot, *shortname, *packagecontext, *oldcontext; dl_funcptr p0; PyObject* (*p)(void); @@ -48,12 +55,16 @@ shortname = lastdot+1; } +#ifdef MS_WINDOWS + p0 = _PyImport_GetDynLoadWindows(shortname, path, fp); +#else pathbytes = PyUnicode_EncodeFSDefault(path); if (pathbytes == NULL) return NULL; p0 = _PyImport_GetDynLoadFunc(shortname, PyBytes_AS_STRING(pathbytes), fp); Py_DECREF(pathbytes); +#endif p = (PyObject*(*)(void))p0; if (PyErr_Occurred()) return NULL; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 4 23:42:34 2011 From: python-checkins at python.org (victor.stinner) Date: Mon, 04 Apr 2011 23:42:34 +0200 Subject: [Python-checkins] cpython: Issue #11765: don't test time.sleep() in test_faulthandler Message-ID: http://hg.python.org/cpython/rev/8da8cd1ba9d9 changeset: 69146:8da8cd1ba9d9 user: Victor Stinner date: Mon Apr 04 23:42:30 2011 +0200 summary: Issue #11765: don't test time.sleep() in test_faulthandler time.time() and/or time.sleep() are not accurate on Windows, don't test them in test_faulthandler. Anyway, the check was written for an old implementation of dump_tracebacks_later(), it is not more needed. files: Lib/test/test_faulthandler.py | 12 ++---------- 1 files changed, 2 insertions(+), 10 deletions(-) diff --git a/Lib/test/test_faulthandler.py b/Lib/test/test_faulthandler.py --- a/Lib/test/test_faulthandler.py +++ b/Lib/test/test_faulthandler.py @@ -360,16 +360,8 @@ def func(repeat, cancel, timeout): if cancel: faulthandler.cancel_dump_tracebacks_later() - - pause = timeout * 2.5 - # on Windows XP, b-a gives 1.249931 after sleep(1.25) - min_pause = pause * 0.9 - a = time.time() - time.sleep(pause) - b = time.time() + time.sleep(timeout * 2.5) faulthandler.cancel_dump_tracebacks_later() - # Check that sleep() was not interrupted - assert (b - a) >= min_pause, "{{}} < {{}}".format(b - a, min_pause) timeout = {timeout} repeat = {repeat} @@ -400,7 +392,7 @@ else: count = 1 header = 'Thread 0x[0-9a-f]+:\n' - regex = expected_traceback(12, 27, header, count=count) + regex = expected_traceback(7, 19, header, count=count) self.assertRegex(trace, regex) else: self.assertEqual(trace, '') -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 5 01:37:19 2011 From: python-checkins at python.org (brett.cannon) Date: Tue, 05 Apr 2011 01:37:19 +0200 Subject: [Python-checkins] peps: Draft of PEP 399: Pure Python/C Accelerator Module Compatibiilty Requirements Message-ID: http://hg.python.org/peps/rev/7b9a5b01b479 changeset: 3855:7b9a5b01b479 user: Brett Cannon date: Mon Apr 04 16:37:07 2011 -0700 summary: Draft of PEP 399: Pure Python/C Accelerator Module Compatibiilty Requirements files: pep-0399.txt | 205 +++++++++++++++++++++++++++++++++++++++ 1 files changed, 205 insertions(+), 0 deletions(-) diff --git a/pep-0399.txt b/pep-0399.txt new file mode 100644 --- /dev/null +++ b/pep-0399.txt @@ -0,0 +1,205 @@ +PEP: 399 +Title: Pure Python/C Accelerator Module Compatibiilty Requirements +Version: $Revision: 88219 $ +Last-Modified: $Date: 2011-01-27 13:47:00 -0800 (Thu, 27 Jan 2011) $ +Author: Brett Cannon +Status: Draft +Type: Informational +Content-Type: text/x-rst +Created: 04-Apr-2011 +Python-Version: 3.3 +Post-History: + +Abstract +======== + +The Python standard library under CPython contains various instances +of modules implemented in both pure Python and C. This PEP requires +that in these instances that both the Python and C code *must* be +semantically identical (except in cases where implementation details +of a VM prevents it entirely). It is also required that new C-based +modules lacking a pure Python equivalent implementation get special +permissions to be added to the standard library. + + +Rationale +========= + +Python has grown beyond the CPython virtual machine (VM). IronPython_, +Jython_, and PyPy_ all currently being viable alternatives to the +CPython VM. This VM ecosystem that has sprung up around the Python +programming language has led to Python being used in many different +areas where CPython cannot be used, e.g., Jython allowing Python to be +used in Java applications. + +A problem all of the VMs other than CPython face is handling modules +from the standard library that are implemented in C. Since they do not +typically support the entire `C API of Python`_ they are unable to use +the code used to create the module. Often times this leads these other +VMs to either re-implement the modules in pure Python or in the +programming language used to implement the VM (e.g., in C# for +IronPython). This duplication of effort between CPython, PyPy, Jython, +and IronPython is extremely unfortunate as implementing a module *at +least* in pure Python would help mitigate this duplicate effort. + +The purpose of this PEP is to minimize this duplicate effort by +mandating that all new modules added to Python's standard library +*must* have a pure Python implementation _unless_ special dispensation +is given. This makes sure that a module in the stdlib is available to +all VMs and not just to CPython. + +Re-implementing parts (or all) of a module in C (in the case +of CPython) is still allowed for performance reasons, but any such +accelerated code must semantically match the pure Python equivalent to +prevent divergence. To accomplish this, the pure Python and C code must +be thoroughly tested with the *same* test suite to verify compliance. +This is to prevent users from accidentally relying +on semantics that are specific to the C code and are not reflected in +the pure Python implementation that other VMs rely upon, e.g., in +CPython 3.2.0, ``heapq.heappop()`` raises different exceptions +depending on whether the accelerated C code is used or not:: + + from test.support import import_fresh_module + + c_heapq = import_fresh_module('heapq', fresh=['_heapq']) + py_heapq = import_fresh_module('heapq', blocked=['_heapq']) + + + class Spam: + """Tester class which defines no other magic methods but + __len__().""" + def __len__(self): + return 0 + + + try: + c_heapq.heappop(Spam()) + except TypeError: + # "heap argument must be a list" + pass + + try: + py_heapq.heappop(Spam()) + except AttributeError: + # "'Foo' object has no attribute 'pop'" + pass + +This kind of divergence is a problem for users as they unwittingly +write code that is CPython-specific. This is also an issue for other +VM teams as they have to deal with bug reports from users thinking +that they incorrectly implemented the module when in fact it was +caused by an untested case. + + +Details +======= + +Starting in Python 3.3, any modules added to the standard library must +have a pure Python implementation. This rule can only be ignored if +the Python development team grants a special exemption for the module. +Typically the exemption would be granted only when a module wraps a +specific C-based library (e.g., sqlite3_). In granting an exemption it +will be recognized that the module will most likely be considered +exclusive to CPython and not part of Python's standard library that +other VMs are expected to support. Usage of ``ctypes`` to provide an +API for a C library will continue to be frowned upon as ``ctypes`` +lacks compiler guarantees that C code typically relies upon to prevent +certain errors from occurring (e.g., API changes). + +Even though a pure Python implementation is mandated by this PEP, it +does not preclude the use of a companion acceleration module. If an +acceleration module is provided it is to be named the same as the +module it is accelerating with an underscore attached as a prefix, +e.g., ``_warnings`` for ``warnings``. The common pattern to access +the accelerated code from the pure Python implementation is to import +it with an ``import *``, e.g., ``from _warnings import *``. This is +typically done at the end of the module to allow it to overwrite +specific Python objects with their accelerated equivalents. This kind +of import can also be done before the end of the module when needed, +e.g., an accelerated base class is provided but is then subclassed by +Python code. This PEP does not mandate that pre-existing modules in +the stdlib that lack a pure Python equivalent gain such a module. But +if people do volunteer to provide and maintain a pure Python +equivalent (e.g., the PyPy team volunteering their pure Python +implementation of the ``csv`` module and maintaining it) then such +code will be accepted. + +Any accelerated code must be semantically identical to the pure Python +implementation. The only time any semantics are allowed to be +different are when technical details of the VM providing the +accelerated code prevent matching semantics from being possible, e.g., +a class being a ``type`` when implemented in C. The semantics +equivalence requirement also dictates that no public API be provided +in accelerated code that does not exist in the pure Python code. +Without this requirement people could accidentally come to rely on a +detail in the acclerated code which is not made available to other VMs +that use the pure Python implementation. To help verify that the +contract of semantic equivalence is being met, a module must be tested +both with and without its accelerated code as thoroughly as possible. + +As an example, to write tests which exercise both the pure Python and +C acclerated versions of a module, a basic idiom can be followed:: + + import collections.abc + from test.support import import_fresh_module, run_unittest + import unittest + + c_heapq = import_fresh_module('heapq', fresh=['_heapq']) + py_heapq = import_fresh_module('heapq', blocked=['_heapq']) + + + class ExampleTest(unittest.TestCase): + + def test_heappop_exc_for_non_MutableSequence(self): + # Raise TypeError when heap is not a + # collections.abc.MutableSequence. + class Spam: + """Test class lacking many ABC-required methods + (e.g., pop()).""" + def __len__(self): + return 0 + + heap = Spam() + self.assertFalse(isinstance(heap, + collections.abc.MutableSequence)) + with self.assertRaises(TypeError): + self.heapq.heappop(heap) + + + class AcceleratedExampleTest(ExampleTest): + + """Test using the acclerated code.""" + + heapq = c_heapq + + + class PyExampleTest(ExampleTest): + + """Test with just the pure Python code.""" + + heapq = py_heapq + + + def test_main(): + run_unittest(AcceleratedExampleTest, PyExampleTest) + + + if __name__ == '__main__': + test_main() + +Thoroughness of the test can be verified using coverage measurements +with branching coverage on the pure Python code to verify that all +possible scenarios are tested using (or not using) accelerator code. + + +Copyright +========= + +This document has been placed in the public domain. + + +.. _IronPython: http://ironpython.net/ +.. _Jython: http://www.jython.org/ +.. _PyPy: http://pypy.org/ +.. _C API of Python: http://docs.python.org/py3k/c-api/index.html +.. _sqlite3: http://docs.python.org/py3k/library/sqlite3.html -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Tue Apr 5 01:47:20 2011 From: python-checkins at python.org (brett.cannon) Date: Tue, 05 Apr 2011 01:47:20 +0200 Subject: [Python-checkins] peps: Fix a spelling mistake in the title of PEP 399 Message-ID: http://hg.python.org/peps/rev/359ccf54bc52 changeset: 3856:359ccf54bc52 user: Brett Cannon date: Mon Apr 04 16:47:09 2011 -0700 summary: Fix a spelling mistake in the title of PEP 399 files: pep-0399.txt | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/pep-0399.txt b/pep-0399.txt --- a/pep-0399.txt +++ b/pep-0399.txt @@ -1,5 +1,5 @@ PEP: 399 -Title: Pure Python/C Accelerator Module Compatibiilty Requirements +Title: Pure Python/C Accelerator Module Compatibility Requirements Version: $Revision: 88219 $ Last-Modified: $Date: 2011-01-27 13:47:00 -0800 (Thu, 27 Jan 2011) $ Author: Brett Cannon -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Tue Apr 5 01:48:20 2011 From: python-checkins at python.org (victor.stinner) Date: Tue, 05 Apr 2011 01:48:20 +0200 Subject: [Python-checkins] cpython: Issue #10785: Store the filename as Unicode in the Python parser. Message-ID: http://hg.python.org/cpython/rev/6e9dc970ac0e changeset: 69147:6e9dc970ac0e user: Victor Stinner date: Tue Apr 05 00:39:01 2011 +0200 summary: Issue #10785: Store the filename as Unicode in the Python parser. files: Include/parsetok.h | 9 +++++- Makefile.pre.in | 7 +++-- Misc/NEWS | 2 + Modules/parsermodule.c | 1 + Parser/parsetok.c | 32 ++++++++++++++++++----- Parser/parsetok_pgen.c | 2 + Parser/tokenizer.c | 35 ++++++++++++++++--------- Parser/tokenizer.h | 8 +++++- Python/pythonrun.c | 40 ++++++++++++++++++------------ 9 files changed, 94 insertions(+), 42 deletions(-) diff --git a/Include/parsetok.h b/Include/parsetok.h --- a/Include/parsetok.h +++ b/Include/parsetok.h @@ -9,7 +9,10 @@ typedef struct { int error; - const char *filename; /* decoded from the filesystem encoding */ +#ifndef PGEN + /* The filename is useless for pgen, see comment in tok_state structure */ + PyObject *filename; +#endif int lineno; int offset; char *text; /* UTF-8-encoded string */ @@ -66,8 +69,10 @@ perrdetail *err_ret, int *flags); -/* Note that he following function is defined in pythonrun.c not parsetok.c. */ +/* Note that the following functions are defined in pythonrun.c, + not in parsetok.c */ PyAPI_FUNC(void) PyParser_SetError(perrdetail *); +PyAPI_FUNC(void) PyParser_ClearError(perrdetail *); #ifdef __cplusplus } diff --git a/Makefile.pre.in b/Makefile.pre.in --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -238,14 +238,13 @@ Parser/listnode.o \ Parser/node.o \ Parser/parser.o \ - Parser/parsetok.o \ Parser/bitset.o \ Parser/metagrammar.o \ Parser/firstsets.o \ Parser/grammar.o \ Parser/pgen.o -PARSER_OBJS= $(POBJS) Parser/myreadline.o Parser/tokenizer.o +PARSER_OBJS= $(POBJS) Parser/myreadline.o Parser/parsetok.o Parser/tokenizer.o PGOBJS= \ Objects/obmalloc.o \ @@ -254,10 +253,12 @@ Python/pyctype.o \ Parser/tokenizer_pgen.o \ Parser/printgrammar.o \ + Parser/parsetok_pgen.o \ Parser/pgenmain.o PARSER_HEADERS= \ Parser/parser.h \ + Include/parsetok.h \ Parser/tokenizer.h PGENOBJS= $(PGENMAIN) $(POBJS) $(PGOBJS) @@ -593,6 +594,7 @@ Parser/metagrammar.o: $(srcdir)/Parser/metagrammar.c Parser/tokenizer_pgen.o: $(srcdir)/Parser/tokenizer.c +Parser/parsetok_pgen.o: $(srcdir)/Parser/parsetok.c Parser/pgenmain.o: $(srcdir)/Include/parsetok.h @@ -700,7 +702,6 @@ Include/objimpl.h \ Include/opcode.h \ Include/osdefs.h \ - Include/parsetok.h \ Include/patchlevel.h \ Include/pgen.h \ Include/pgenheaders.h \ diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,8 @@ Core and Builtins ----------------- +- Issue #10785: Store the filename as Unicode in the Python parser. + - Issue #11619: _PyImport_LoadDynamicModule() doesn't encode the path to bytes on Windows. diff --git a/Modules/parsermodule.c b/Modules/parsermodule.c --- a/Modules/parsermodule.c +++ b/Modules/parsermodule.c @@ -584,6 +584,7 @@ else PyParser_SetError(&err); } + PyParser_ClearError(&err); return (res); } diff --git a/Parser/parsetok.c b/Parser/parsetok.c --- a/Parser/parsetok.c +++ b/Parser/parsetok.c @@ -13,7 +13,7 @@ /* Forward */ static node *parsetok(struct tok_state *, grammar *, int, perrdetail *, int *); -static void initerr(perrdetail *err_ret, const char* filename); +static int initerr(perrdetail *err_ret, const char* filename); /* Parse input coming from a string. Return error code, print some errors. */ node * @@ -48,7 +48,8 @@ struct tok_state *tok; int exec_input = start == file_input; - initerr(err_ret, filename); + if (initerr(err_ret, filename) < 0) + return NULL; if (*flags & PyPARSE_IGNORE_COOKIE) tok = PyTokenizer_FromUTF8(s, exec_input); @@ -59,7 +60,10 @@ return NULL; } - tok->filename = filename ? filename : ""; +#ifndef PGEN + Py_INCREF(err_ret->filename); + tok->filename = err_ret->filename; +#endif return parsetok(tok, g, start, err_ret, flags); } @@ -90,13 +94,17 @@ { struct tok_state *tok; - initerr(err_ret, filename); + if (initerr(err_ret, filename) < 0) + return NULL; if ((tok = PyTokenizer_FromFile(fp, (char *)enc, ps1, ps2)) == NULL) { err_ret->error = E_NOMEM; return NULL; } - tok->filename = filename; +#ifndef PGEN + Py_INCREF(err_ret->filename); + tok->filename = err_ret->filename; +#endif return parsetok(tok, g, start, err_ret, flags); } @@ -267,14 +275,24 @@ return n; } -static void +static int initerr(perrdetail *err_ret, const char *filename) { err_ret->error = E_OK; - err_ret->filename = filename; err_ret->lineno = 0; err_ret->offset = 0; err_ret->text = NULL; err_ret->token = -1; err_ret->expected = -1; +#ifndef PGEN + if (filename) + err_ret->filename = PyUnicode_DecodeFSDefault(filename); + else + err_ret->filename = PyUnicode_FromString(""); + if (err_ret->filename == NULL) { + err_ret->error = E_ERROR; + return -1; + } +#endif + return 0; } diff --git a/Parser/parsetok_pgen.c b/Parser/parsetok_pgen.c new file mode 100644 --- /dev/null +++ b/Parser/parsetok_pgen.c @@ -0,0 +1,2 @@ +#define PGEN +#include "parsetok.c" diff --git a/Parser/tokenizer.c b/Parser/tokenizer.c --- a/Parser/tokenizer.c +++ b/Parser/tokenizer.c @@ -128,7 +128,6 @@ tok->prompt = tok->nextprompt = NULL; tok->lineno = 0; tok->level = 0; - tok->filename = NULL; tok->altwarning = 1; tok->alterror = 1; tok->alttabsize = 1; @@ -140,6 +139,7 @@ tok->encoding = NULL; tok->cont_line = 0; #ifndef PGEN + tok->filename = NULL; tok->decoding_readline = NULL; tok->decoding_buffer = NULL; #endif @@ -545,7 +545,6 @@ { char *line = NULL; int badchar = 0; - PyObject *filename; for (;;) { if (tok->decoding_state == STATE_NORMAL) { /* We already have a codec associated with @@ -586,16 +585,12 @@ if (badchar) { /* Need to add 1 to the line number, since this line has not been counted, yet. */ - filename = PyUnicode_DecodeFSDefault(tok->filename); - if (filename != NULL) { - PyErr_Format(PyExc_SyntaxError, - "Non-UTF-8 code starting with '\\x%.2x' " - "in file %U on line %i, " - "but no encoding declared; " - "see http://python.org/dev/peps/pep-0263/ for details", - badchar, filename, tok->lineno + 1); - Py_DECREF(filename); - } + PyErr_Format(PyExc_SyntaxError, + "Non-UTF-8 code starting with '\\x%.2x' " + "in file %U on line %i, " + "but no encoding declared; " + "see http://python.org/dev/peps/pep-0263/ for details", + badchar, tok->filename, tok->lineno + 1); return error_ret(tok); } #endif @@ -853,6 +848,7 @@ #ifndef PGEN Py_XDECREF(tok->decoding_readline); Py_XDECREF(tok->decoding_buffer); + Py_XDECREF(tok->filename); #endif if (tok->fp != NULL && tok->buf != NULL) PyMem_FREE(tok->buf); @@ -1247,8 +1243,13 @@ return 1; } if (tok->altwarning) { - PySys_WriteStderr("%s: inconsistent use of tabs and spaces " +#ifdef PGEN + PySys_WriteStderr("inconsistent use of tabs and spaces " + "in indentation\n"); +#else + PySys_FormatStderr("%U: inconsistent use of tabs and spaces " "in indentation\n", tok->filename); +#endif tok->altwarning = 0; } return 0; @@ -1718,6 +1719,11 @@ fclose(fp); return NULL; } +#ifndef PGEN + tok->filename = PyUnicode_FromString(""); + if (tok->filename == NULL) + goto error; +#endif while (tok->lineno < 2 && tok->done == E_OK) { PyTokenizer_Get(tok, &p_start, &p_end); } @@ -1727,6 +1733,9 @@ if (encoding) strcpy(encoding, tok->encoding); } +#ifndef PGEN +error: +#endif PyTokenizer_Free(tok); return encoding; } diff --git a/Parser/tokenizer.h b/Parser/tokenizer.h --- a/Parser/tokenizer.h +++ b/Parser/tokenizer.h @@ -40,7 +40,13 @@ int level; /* () [] {} Parentheses nesting level */ /* Used to allow free continuations inside them */ /* Stuff for checking on different tab sizes */ - const char *filename; /* encoded to the filesystem encoding */ +#ifndef PGEN + /* pgen doesn't have access to Python codecs, it cannot decode the input + filename. The bytes filename might be kept, but it is only used by + indenterror() and it is not really needed: pgen only compiles one file + (Grammar/Grammar). */ + PyObject *filename; +#endif int altwarning; /* Issue warning if alternate tabs don't match */ int alterror; /* Issue error if alternate tabs don't match */ int alttabsize; /* Alternate tab spacing */ diff --git a/Python/pythonrun.c b/Python/pythonrun.c --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -62,6 +62,7 @@ static PyObject *run_pyc_file(FILE *, const char *, PyObject *, PyObject *, PyCompilerFlags *); static void err_input(perrdetail *); +static void err_free(perrdetail *); static void initsigs(void); static void call_py_exitfuncs(void); static void wait_for_thread_shutdown(void); @@ -1887,12 +1888,13 @@ flags->cf_flags |= iflags & PyCF_MASK; mod = PyAST_FromNode(n, flags, filename, arena); PyNode_Free(n); - return mod; } else { err_input(&err); - return NULL; + mod = NULL; } + err_free(&err); + return mod; } mod_ty @@ -1917,14 +1919,15 @@ flags->cf_flags |= iflags & PyCF_MASK; mod = PyAST_FromNode(n, flags, filename, arena); PyNode_Free(n); - return mod; } else { err_input(&err); if (errcode) *errcode = err.error; - return NULL; + mod = NULL; } + err_free(&err); + return mod; } /* Simplified interface to parsefile -- return node or set exception */ @@ -1938,6 +1941,7 @@ start, NULL, NULL, &err, flags); if (n == NULL) err_input(&err); + err_free(&err); return n; } @@ -1952,6 +1956,7 @@ start, &err, flags); if (n == NULL) err_input(&err); + err_free(&err); return n; } @@ -1964,6 +1969,7 @@ &_PyParser_Grammar, start, &err, flags); if (n == NULL) err_input(&err); + err_free(&err); return n; } @@ -1977,11 +1983,23 @@ even parser modules. */ void +PyParser_ClearError(perrdetail *err) +{ + err_free(err); +} + +void PyParser_SetError(perrdetail *err) { err_input(err); } +static void +err_free(perrdetail *err) +{ + Py_CLEAR(err->filename); +} + /* Set the error appropriate to the given input error code (see errcode.h) */ static void @@ -1989,7 +2007,6 @@ { PyObject *v, *w, *errtype, *errtext; PyObject *msg_obj = NULL; - PyObject *filename; char *msg = NULL; errtype = PyExc_SyntaxError; @@ -2075,17 +2092,8 @@ errtext = PyUnicode_DecodeUTF8(err->text, strlen(err->text), "replace"); } - if (err->filename != NULL) - filename = PyUnicode_DecodeFSDefault(err->filename); - else { - Py_INCREF(Py_None); - filename = Py_None; - } - if (filename != NULL) - v = Py_BuildValue("(NiiN)", filename, - err->lineno, err->offset, errtext); - else - v = NULL; + v = Py_BuildValue("(OiiN)", err->filename, + err->lineno, err->offset, errtext); if (v != NULL) { if (msg_obj) w = Py_BuildValue("(OO)", msg_obj, v); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 5 01:48:35 2011 From: python-checkins at python.org (victor.stinner) Date: Tue, 05 Apr 2011 01:48:35 +0200 Subject: [Python-checkins] cpython: Issue #9319: Include the filename in "Non-UTF8 code ..." syntax error. Message-ID: http://hg.python.org/cpython/rev/7b8d625eb6e4 changeset: 69148:7b8d625eb6e4 user: Victor Stinner date: Tue Apr 05 01:48:03 2011 +0200 summary: Issue #9319: Include the filename in "Non-UTF8 code ..." syntax error. files: Lib/test/test_imp.py | 6 ++++ Misc/NEWS | 2 + Parser/tokenizer.c | 41 +++++++++++++++++++++---------- Parser/tokenizer.h | 1 - Python/import.c | 10 +++--- Python/traceback.c | 6 ++-- 6 files changed, 43 insertions(+), 23 deletions(-) diff --git a/Lib/test/test_imp.py b/Lib/test/test_imp.py --- a/Lib/test/test_imp.py +++ b/Lib/test/test_imp.py @@ -58,6 +58,12 @@ with imp.find_module('module_' + mod, self.test_path)[0] as fd: self.assertEqual(fd.encoding, encoding) + path = [os.path.dirname(__file__)] + self.assertRaisesRegex(SyntaxError, + r"Non-UTF-8 code starting with '\\xf6'" + r" in file .*badsyntax_pep3120.py", + imp.find_module, 'badsyntax_pep3120', path) + def test_issue1267(self): for mod, encoding, _ in self.test_strings: fp, filename, info = imp.find_module('module_' + mod, diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,8 @@ Core and Builtins ----------------- +- Issue #9319: Include the filename in "Non-UTF8 code ..." syntax error. + - Issue #10785: Store the filename as Unicode in the Python parser. - Issue #11619: _PyImport_LoadDynamicModule() doesn't encode the path to bytes diff --git a/Parser/tokenizer.c b/Parser/tokenizer.c --- a/Parser/tokenizer.c +++ b/Parser/tokenizer.c @@ -1690,17 +1690,18 @@ return result; } -/* Get -*- encoding -*- from a Python file. +/* Get the encoding of a Python file. Check for the coding cookie and check if + the file starts with a BOM. - PyTokenizer_FindEncoding returns NULL when it can't find the encoding in - the first or second line of the file (in which case the encoding - should be assumed to be PyUnicode_GetDefaultEncoding()). + PyTokenizer_FindEncodingFilename() returns NULL when it can't find the + encoding in the first or second line of the file (in which case the encoding + should be assumed to be UTF-8). - The char * returned is malloc'ed via PyMem_MALLOC() and thus must be freed - by the caller. -*/ + The char* returned is malloc'ed via PyMem_MALLOC() and thus must be freed + by the caller. */ + char * -PyTokenizer_FindEncoding(int fd) +PyTokenizer_FindEncodingFilename(int fd, PyObject *filename) { struct tok_state *tok; FILE *fp; @@ -1720,9 +1721,18 @@ return NULL; } #ifndef PGEN - tok->filename = PyUnicode_FromString(""); - if (tok->filename == NULL) - goto error; + if (filename != NULL) { + Py_INCREF(filename); + tok->filename = filename; + } + else { + tok->filename = PyUnicode_FromString(""); + if (tok->filename == NULL) { + fclose(fp); + PyTokenizer_Free(tok); + return encoding; + } + } #endif while (tok->lineno < 2 && tok->done == E_OK) { PyTokenizer_Get(tok, &p_start, &p_end); @@ -1733,13 +1743,16 @@ if (encoding) strcpy(encoding, tok->encoding); } -#ifndef PGEN -error: -#endif PyTokenizer_Free(tok); return encoding; } +char * +PyTokenizer_FindEncoding(int fd) +{ + return PyTokenizer_FindEncodingFilename(fd, NULL); +} + #ifdef Py_DEBUG void diff --git a/Parser/tokenizer.h b/Parser/tokenizer.h --- a/Parser/tokenizer.h +++ b/Parser/tokenizer.h @@ -75,7 +75,6 @@ extern int PyTokenizer_Get(struct tok_state *, char **, char **); extern char * PyTokenizer_RestoreEncoding(struct tok_state* tok, int len, int *offset); -extern char * PyTokenizer_FindEncoding(int); #ifdef __cplusplus } diff --git a/Python/import.c b/Python/import.c --- a/Python/import.c +++ b/Python/import.c @@ -124,12 +124,12 @@ /* See _PyImport_FixupExtensionObject() below */ static PyObject *extensions = NULL; +/* Function from Parser/tokenizer.c */ +extern char * PyTokenizer_FindEncodingFilename(int, PyObject *); + /* This table is defined in config.c: */ extern struct _inittab _PyImport_Inittab[]; -/* Method from Parser/tokenizer.c */ -extern char * PyTokenizer_FindEncoding(int); - struct _inittab *PyImport_Inittab = _PyImport_Inittab; /* these tables define the module suffixes that Python recognizes */ @@ -3540,9 +3540,9 @@ } if (fd != -1) { if (strchr(fdp->mode, 'b') == NULL) { - /* PyTokenizer_FindEncoding() returns PyMem_MALLOC'ed + /* PyTokenizer_FindEncodingFilename() returns PyMem_MALLOC'ed memory. */ - found_encoding = PyTokenizer_FindEncoding(fd); + found_encoding = PyTokenizer_FindEncodingFilename(fd, pathobj); lseek(fd, 0, 0); /* Reset position */ if (found_encoding == NULL && PyErr_Occurred()) { Py_XDECREF(pathobj); diff --git a/Python/traceback.c b/Python/traceback.c --- a/Python/traceback.c +++ b/Python/traceback.c @@ -18,8 +18,8 @@ #define MAX_FRAME_DEPTH 100 #define MAX_NTHREADS 100 -/* Method from Parser/tokenizer.c */ -extern char * PyTokenizer_FindEncoding(int); +/* Function from Parser/tokenizer.c */ +extern char * PyTokenizer_FindEncodingFilename(int, PyObject *); static PyObject * tb_dir(PyTracebackObject *self) @@ -251,7 +251,7 @@ /* use the right encoding to decode the file as unicode */ fd = PyObject_AsFileDescriptor(binary); - found_encoding = PyTokenizer_FindEncoding(fd); + found_encoding = PyTokenizer_FindEncodingFilename(fd, filename); encoding = (found_encoding != NULL) ? found_encoding : "utf-8"; lseek(fd, 0, 0); /* Reset position */ fob = PyObject_CallMethod(io, "TextIOWrapper", "Os", binary, encoding); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 5 02:30:07 2011 From: python-checkins at python.org (victor.stinner) Date: Tue, 05 Apr 2011 02:30:07 +0200 Subject: [Python-checkins] cpython: Issue #11768: add debug messages in test_threadsignals.test_signals Message-ID: http://hg.python.org/cpython/rev/d14eac872a46 changeset: 69149:d14eac872a46 user: Victor Stinner date: Tue Apr 05 02:29:30 2011 +0200 summary: Issue #11768: add debug messages in test_threadsignals.test_signals files: Lib/test/test_threadsignals.py | 8 ++++++++ 1 files changed, 8 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_threadsignals.py b/Lib/test/test_threadsignals.py --- a/Lib/test/test_threadsignals.py +++ b/Lib/test/test_threadsignals.py @@ -30,9 +30,14 @@ # a function that will be spawned as a separate thread. def send_signals(): + print("send_signals: enter (thread %s)" % thread.get_ident(), file=sys.stderr) + print("send_signals: raise SIGUSR1", file=sys.stderr) os.kill(process_pid, signal.SIGUSR1) + print("send_signals: raise SIGUSR2", file=sys.stderr) os.kill(process_pid, signal.SIGUSR2) + print("send_signals: release signalled_all", file=sys.stderr) signalled_all.release() + print("send_signals: exit (thread %s)" % thread.get_ident(), file=sys.stderr) class ThreadSignals(unittest.TestCase): @@ -41,9 +46,12 @@ # We spawn a thread, have the thread send two signals, and # wait for it to finish. Check that we got both signals # and that they were run by the main thread. + print("test_signals: acquire lock (thread %s)" % thread.get_ident(), file=sys.stderr) signalled_all.acquire() self.spawnSignallingThread() + print("test_signals: wait lock (thread %s)" % thread.get_ident(), file=sys.stderr) signalled_all.acquire() + print("test_signals: lock acquired", file=sys.stderr) # the signals that we asked the kernel to send # will come back, but we don't know when. # (it might even be after the thread exits -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Tue Apr 5 04:55:50 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Tue, 05 Apr 2011 04:55:50 +0200 Subject: [Python-checkins] Daily reference leaks (d14eac872a46): sum=0 Message-ID: results for d14eac872a46 on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogrsldRs', '-x'] From python-checkins at python.org Tue Apr 5 11:34:06 2011 From: python-checkins at python.org (raymond.hettinger) Date: Tue, 05 Apr 2011 11:34:06 +0200 Subject: [Python-checkins] cpython: Issue #11707: Fast C version of functools.cmp_to_key() Message-ID: http://hg.python.org/cpython/rev/a03fb2fc3ed8 changeset: 69150:a03fb2fc3ed8 user: Raymond Hettinger date: Tue Apr 05 02:33:54 2011 -0700 summary: Issue #11707: Fast C version of functools.cmp_to_key() files: Lib/functools.py | 7 +- Lib/test/test_functools.py | 66 ++++++++++- Misc/NEWS | 3 + Modules/_functoolsmodule.c | 161 +++++++++++++++++++++++++ 4 files changed, 235 insertions(+), 2 deletions(-) diff --git a/Lib/functools.py b/Lib/functools.py --- a/Lib/functools.py +++ b/Lib/functools.py @@ -97,7 +97,7 @@ """Convert a cmp= function into a key= function""" class K(object): __slots__ = ['obj'] - def __init__(self, obj, *args): + def __init__(self, obj): self.obj = obj def __lt__(self, other): return mycmp(self.obj, other.obj) < 0 @@ -115,6 +115,11 @@ raise TypeError('hash not implemented') return K +try: + from _functools import cmp_to_key +except ImportError: + pass + _CacheInfo = namedtuple("CacheInfo", "hits misses maxsize currsize") def lru_cache(maxsize=100): diff --git a/Lib/test/test_functools.py b/Lib/test/test_functools.py --- a/Lib/test/test_functools.py +++ b/Lib/test/test_functools.py @@ -435,18 +435,81 @@ self.assertEqual(self.func(add, d), "".join(d.keys())) class TestCmpToKey(unittest.TestCase): + def test_cmp_to_key(self): + def cmp1(x, y): + return (x > y) - (x < y) + key = functools.cmp_to_key(cmp1) + self.assertEqual(key(3), key(3)) + self.assertGreater(key(3), key(1)) + def cmp2(x, y): + return int(x) - int(y) + key = functools.cmp_to_key(cmp2) + self.assertEqual(key(4.0), key('4')) + self.assertLess(key(2), key('35')) + + def test_cmp_to_key_arguments(self): + def cmp1(x, y): + return (x > y) - (x < y) + key = functools.cmp_to_key(mycmp=cmp1) + self.assertEqual(key(obj=3), key(obj=3)) + self.assertGreater(key(obj=3), key(obj=1)) + with self.assertRaises((TypeError, AttributeError)): + key(3) > 1 # rhs is not a K object + with self.assertRaises((TypeError, AttributeError)): + 1 < key(3) # lhs is not a K object + with self.assertRaises(TypeError): + key = functools.cmp_to_key() # too few args + with self.assertRaises(TypeError): + key = functools.cmp_to_key(cmp1, None) # too many args + key = functools.cmp_to_key(cmp1) + with self.assertRaises(TypeError): + key() # too few args + with self.assertRaises(TypeError): + key(None, None) # too many args + + def test_bad_cmp(self): + def cmp1(x, y): + raise ZeroDivisionError + key = functools.cmp_to_key(cmp1) + with self.assertRaises(ZeroDivisionError): + key(3) > key(1) + + class BadCmp: + def __lt__(self, other): + raise ZeroDivisionError + def cmp1(x, y): + return BadCmp() + with self.assertRaises(ZeroDivisionError): + key(3) > key(1) + + def test_obj_field(self): + def cmp1(x, y): + return (x > y) - (x < y) + key = functools.cmp_to_key(mycmp=cmp1) + self.assertEqual(key(50).obj, 50) + + def test_sort_int(self): def mycmp(x, y): return y - x self.assertEqual(sorted(range(5), key=functools.cmp_to_key(mycmp)), [4, 3, 2, 1, 0]) + def test_sort_int_str(self): + def mycmp(x, y): + x, y = int(x), int(y) + return (x > y) - (x < y) + values = [5, '3', 7, 2, '0', '1', 4, '10', 1] + values = sorted(values, key=functools.cmp_to_key(mycmp)) + self.assertEqual([int(value) for value in values], + [0, 1, 1, 2, 3, 4, 5, 7, 10]) + def test_hash(self): def mycmp(x, y): return y - x key = functools.cmp_to_key(mycmp) k = key(10) - self.assertRaises(TypeError, hash(k)) + self.assertRaises(TypeError, hash, k) class TestTotalOrdering(unittest.TestCase): @@ -655,6 +718,7 @@ def test_main(verbose=None): test_classes = ( + TestCmpToKey, TestPartial, TestPartialSubclass, TestPythonPartial, diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -97,6 +97,9 @@ - Issue #10791: Implement missing method GzipFile.read1(), allowing GzipFile to be wrapped in a TextIOWrapper. Patch by Nadeem Vawda. +- Issue #11707: Added a fast C version of functools.cmp_to_key(). + Patch by Filip Gruszczy?ski. + - Issue #11688: Add sqlite3.Connection.set_trace_callback(). Patch by Torsten Landschoff. diff --git a/Modules/_functoolsmodule.c b/Modules/_functoolsmodule.c --- a/Modules/_functoolsmodule.c +++ b/Modules/_functoolsmodule.c @@ -330,6 +330,165 @@ }; +/* cmp_to_key ***************************************************************/ + +typedef struct { + PyObject_HEAD; + PyObject *cmp; + PyObject *object; +} keyobject; + +static void +keyobject_dealloc(keyobject *ko) +{ + Py_DECREF(ko->cmp); + Py_XDECREF(ko->object); + PyObject_FREE(ko); +} + +static int +keyobject_traverse(keyobject *ko, visitproc visit, void *arg) +{ + Py_VISIT(ko->cmp); + if (ko->object) + Py_VISIT(ko->object); + return 0; +} + +static PyMemberDef keyobject_members[] = { + {"obj", T_OBJECT, + offsetof(keyobject, object), 0, + PyDoc_STR("Value wrapped by a key function.")}, + {NULL} +}; + +static PyObject * +keyobject_call(keyobject *ko, PyObject *args, PyObject *kw); + +static PyObject * +keyobject_richcompare(PyObject *ko, PyObject *other, int op); + +static PyTypeObject keyobject_type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "functools.KeyWrapper", /* tp_name */ + sizeof(keyobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)keyobject_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_reserved */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + (ternaryfunc)keyobject_call, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + 0, /* tp_doc */ + (traverseproc)keyobject_traverse, /* tp_traverse */ + 0, /* tp_clear */ + keyobject_richcompare, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + keyobject_members, /* tp_members */ + 0, /* tp_getset */ +}; + +static PyObject * +keyobject_call(keyobject *ko, PyObject *args, PyObject *kwds) +{ + PyObject *object; + keyobject *result; + static char *kwargs[] = {"obj", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:K", kwargs, &object)) + return NULL; + result = PyObject_New(keyobject, &keyobject_type); + if (!result) + return NULL; + Py_INCREF(ko->cmp); + result->cmp = ko->cmp; + Py_INCREF(object); + result->object = object; + return (PyObject *)result; +} + +static PyObject * +keyobject_richcompare(PyObject *ko, PyObject *other, int op) +{ + PyObject *res; + PyObject *args; + PyObject *x; + PyObject *y; + PyObject *compare; + PyObject *answer; + static PyObject *zero; + + if (zero == NULL) { + zero = PyLong_FromLong(0); + if (!zero) + return NULL; + } + + if (Py_TYPE(other) != &keyobject_type){ + PyErr_Format(PyExc_TypeError, "other argument must be K instance"); + return NULL; + } + compare = ((keyobject *) ko)->cmp; + assert(compare != NULL); + x = ((keyobject *) ko)->object; + y = ((keyobject *) other)->object; + if (!x || !y){ + PyErr_Format(PyExc_AttributeError, "object"); + return NULL; + } + + /* Call the user's comparison function and translate the 3-way + * result into true or false (or error). + */ + args = PyTuple_New(2); + if (args == NULL) + return NULL; + Py_INCREF(x); + Py_INCREF(y); + PyTuple_SET_ITEM(args, 0, x); + PyTuple_SET_ITEM(args, 1, y); + res = PyObject_Call(compare, args, NULL); + Py_DECREF(args); + if (res == NULL) + return NULL; + answer = PyObject_RichCompare(res, zero, op); + Py_DECREF(res); + return answer; +} + +static PyObject * +functools_cmp_to_key(PyObject *self, PyObject *args, PyObject *kwds){ + PyObject *cmp; + static char *kwargs[] = {"mycmp", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:cmp_to_key", kwargs, &cmp)) + return NULL; + keyobject *object = PyObject_New(keyobject, &keyobject_type); + if (!object) + return NULL; + Py_INCREF(cmp); + object->cmp = cmp; + object->object = NULL; + return (PyObject *)object; +} + +PyDoc_STRVAR(functools_cmp_to_key_doc, +"Convert a cmp= function into a key= function."); + /* reduce (used to be a builtin) ********************************************/ static PyObject * @@ -413,6 +572,8 @@ static PyMethodDef module_methods[] = { {"reduce", functools_reduce, METH_VARARGS, functools_reduce_doc}, + {"cmp_to_key", functools_cmp_to_key, METH_VARARGS | METH_KEYWORDS, + functools_cmp_to_key_doc}, {NULL, NULL} /* sentinel */ }; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 5 12:21:51 2011 From: python-checkins at python.org (victor.stinner) Date: Tue, 05 Apr 2011 12:21:51 +0200 Subject: [Python-checkins] cpython: Issue #11707: Fix compilation errors with Visual Studio Message-ID: http://hg.python.org/cpython/rev/76ed6a061ebe changeset: 69151:76ed6a061ebe user: Victor Stinner date: Tue Apr 05 12:21:35 2011 +0200 summary: Issue #11707: Fix compilation errors with Visual Studio Fix also a compiler (gcc) warning. files: Modules/_functoolsmodule.c | 14 ++++++++------ 1 files changed, 8 insertions(+), 6 deletions(-) diff --git a/Modules/_functoolsmodule.c b/Modules/_functoolsmodule.c --- a/Modules/_functoolsmodule.c +++ b/Modules/_functoolsmodule.c @@ -333,7 +333,7 @@ /* cmp_to_key ***************************************************************/ typedef struct { - PyObject_HEAD; + PyObject_HEAD PyObject *cmp; PyObject *object; } keyobject; @@ -471,13 +471,15 @@ } static PyObject * -functools_cmp_to_key(PyObject *self, PyObject *args, PyObject *kwds){ - PyObject *cmp; +functools_cmp_to_key(PyObject *self, PyObject *args, PyObject *kwds) +{ + PyObject *cmp; static char *kwargs[] = {"mycmp", NULL}; + keyobject *object; if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:cmp_to_key", kwargs, &cmp)) return NULL; - keyobject *object = PyObject_New(keyobject, &keyobject_type); + object = PyObject_New(keyobject, &keyobject_type); if (!object) return NULL; Py_INCREF(cmp); @@ -572,8 +574,8 @@ static PyMethodDef module_methods[] = { {"reduce", functools_reduce, METH_VARARGS, functools_reduce_doc}, - {"cmp_to_key", functools_cmp_to_key, METH_VARARGS | METH_KEYWORDS, - functools_cmp_to_key_doc}, + {"cmp_to_key", (PyCFunction)functools_cmp_to_key, + METH_VARARGS | METH_KEYWORDS, functools_cmp_to_key_doc}, {NULL, NULL} /* sentinel */ }; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 5 13:16:12 2011 From: python-checkins at python.org (victor.stinner) Date: Tue, 05 Apr 2011 13:16:12 +0200 Subject: [Python-checkins] cpython: Issue #11757: subprocess ensures that select() and poll() timeout >= 0 Message-ID: http://hg.python.org/cpython/rev/3664fc29e867 changeset: 69152:3664fc29e867 user: Victor Stinner date: Tue Apr 05 13:13:08 2011 +0200 summary: Issue #11757: subprocess ensures that select() and poll() timeout >= 0 files: Lib/subprocess.py | 33 +++++++++++++++++++-------------- 1 files changed, 19 insertions(+), 14 deletions(-) diff --git a/Lib/subprocess.py b/Lib/subprocess.py --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -817,15 +817,10 @@ if self._communication_started and input: raise ValueError("Cannot send input after starting communication") - if timeout is not None: - endtime = time.time() + timeout - else: - endtime = None - # Optimization: If we are not worried about timeouts, we haven't # started communicating, and we have one or zero pipes, using select() # or threads is unnecessary. - if (endtime is None and not self._communication_started and + if (timeout is None and not self._communication_started and [self.stdin, self.stdout, self.stderr].count(None) >= 2): stdout = None stderr = None @@ -840,14 +835,18 @@ stderr = self.stderr.read() self.stderr.close() self.wait() - return (stdout, stderr) + else: + if timeout is not None: + endtime = time.time() + timeout + else: + endtime = None - try: - stdout, stderr = self._communicate(input, endtime, timeout) - finally: - self._communication_started = True + try: + stdout, stderr = self._communicate(input, endtime, timeout) + finally: + self._communication_started = True - sts = self.wait(timeout=self._remaining_time(endtime)) + sts = self.wait(timeout=self._remaining_time(endtime)) return (stdout, stderr) @@ -1604,8 +1603,11 @@ self._input = self._input.encode(self.stdin.encoding) while self._fd2file: + timeout = self._remaining_time(endtime) + if timeout is not None and timeout < 0: + raise TimeoutExpired(self.args, orig_timeout) try: - ready = poller.poll(self._remaining_time(endtime)) + ready = poller.poll(timeout) except select.error as e: if e.args[0] == errno.EINTR: continue @@ -1664,10 +1666,13 @@ stderr = self._stderr_buff while self._read_set or self._write_set: + timeout = self._remaining_time(endtime) + if timeout is not None and timeout < 0: + raise TimeoutExpired(self.args, orig_timeout) try: (rlist, wlist, xlist) = \ select.select(self._read_set, self._write_set, [], - self._remaining_time(endtime)) + timeout) except select.error as e: if e.args[0] == errno.EINTR: continue -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 5 16:10:14 2011 From: python-checkins at python.org (ross.lagerwall) Date: Tue, 05 Apr 2011 16:10:14 +0200 Subject: [Python-checkins] cpython (2.7): Issue #10963: Ensure that subprocess.communicate() never raises EPIPE. Message-ID: http://hg.python.org/cpython/rev/c10d55c51d81 changeset: 69153:c10d55c51d81 branch: 2.7 parent: 69125:f961e9179998 user: Ross Lagerwall date: Tue Apr 05 15:24:34 2011 +0200 summary: Issue #10963: Ensure that subprocess.communicate() never raises EPIPE. files: Lib/subprocess.py | 45 ++++++++++++++++++------ Lib/test/test_subprocess.py | 18 ++++++++++ Misc/NEWS | 2 + 3 files changed, 54 insertions(+), 11 deletions(-) diff --git a/Lib/subprocess.py b/Lib/subprocess.py --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -396,6 +396,7 @@ import traceback import gc import signal +import errno # Exception classes used by this module. class CalledProcessError(Exception): @@ -427,7 +428,6 @@ else: import select _has_poll = hasattr(select, 'poll') - import errno import fcntl import pickle @@ -726,7 +726,11 @@ stderr = None if self.stdin: if input: - self.stdin.write(input) + try: + self.stdin.write(input) + except IOError as e: + if e.errno != errno.EPIPE and e.errno != errno.EINVAL: + raise self.stdin.close() elif self.stdout: stdout = self.stdout.read() @@ -956,7 +960,11 @@ if self.stdin: if input is not None: - self.stdin.write(input) + try: + self.stdin.write(input) + except IOError as e: + if e.errno != errno.EPIPE: + raise self.stdin.close() if self.stdout: @@ -1336,9 +1344,16 @@ for fd, mode in ready: if mode & select.POLLOUT: chunk = input[input_offset : input_offset + _PIPE_BUF] - input_offset += os.write(fd, chunk) - if input_offset >= len(input): - close_unregister_and_remove(fd) + try: + input_offset += os.write(fd, chunk) + except OSError as e: + if e.errno == errno.EPIPE: + close_unregister_and_remove(fd) + else: + raise + else: + if input_offset >= len(input): + close_unregister_and_remove(fd) elif mode & select_POLLIN_POLLPRI: data = os.read(fd, 4096) if not data: @@ -1377,11 +1392,19 @@ if self.stdin in wlist: chunk = input[input_offset : input_offset + _PIPE_BUF] - bytes_written = os.write(self.stdin.fileno(), chunk) - input_offset += bytes_written - if input_offset >= len(input): - self.stdin.close() - write_set.remove(self.stdin) + try: + bytes_written = os.write(self.stdin.fileno(), chunk) + except OSError as e: + if e.errno == errno.EPIPE: + self.stdin.close() + write_set.remove(self.stdin) + else: + raise + else: + input_offset += bytes_written + if input_offset >= len(input): + self.stdin.close() + write_set.remove(self.stdin) if self.stdout in rlist: data = os.read(self.stdout.fileno(), 1024) diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -597,6 +597,24 @@ self.assertFalse(os.path.exists(ofname)) self.assertFalse(os.path.exists(efname)) + def test_communicate_epipe(self): + # Issue 10963: communicate() should hide EPIPE + p = subprocess.Popen([sys.executable, "-c", 'pass'], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + self.addCleanup(p.stdout.close) + self.addCleanup(p.stderr.close) + self.addCleanup(p.stdin.close) + p.communicate("x" * 2**20) + + def test_communicate_epipe_only_stdin(self): + # Issue 10963: communicate() should hide EPIPE + p = subprocess.Popen([sys.executable, "-c", 'pass'], + stdin=subprocess.PIPE) + self.addCleanup(p.stdin.close) + time.sleep(2) + p.communicate("x" * 2**20) # context manager class _SuppressCoreFiles(object): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -47,6 +47,8 @@ Library ------- +- Issue #10963: Ensure that subprocess.communicate() never raises EPIPE. + - Issue #11662: Make urllib and urllib2 ignore redirections if the scheme is not HTTP, HTTPS or FTP (CVE-2011-1521). -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 5 16:10:21 2011 From: python-checkins at python.org (ross.lagerwall) Date: Tue, 05 Apr 2011 16:10:21 +0200 Subject: [Python-checkins] cpython (3.1): Issue #10963: Ensure that subprocess.communicate() never raises EPIPE. Message-ID: http://hg.python.org/cpython/rev/158495d49f58 changeset: 69154:158495d49f58 branch: 3.1 parent: 69142:04b5cd2f8c87 user: Ross Lagerwall date: Tue Apr 05 15:34:00 2011 +0200 summary: Issue #10963: Ensure that subprocess.communicate() never raises EPIPE. files: Lib/subprocess.py | 45 ++++++++++++++++++------ Lib/test/test_subprocess.py | 19 ++++++++++ Misc/NEWS | 2 + 3 files changed, 55 insertions(+), 11 deletions(-) diff --git a/Lib/subprocess.py b/Lib/subprocess.py --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -326,6 +326,7 @@ import traceback import gc import signal +import errno # Exception classes used by this module. class CalledProcessError(Exception): @@ -358,7 +359,6 @@ else: import select _has_poll = hasattr(select, 'poll') - import errno import fcntl import pickle @@ -699,7 +699,11 @@ stderr = None if self.stdin: if input: - self.stdin.write(input) + try: + self.stdin.write(input) + except IOError as e: + if e.errno != errno.EPIPE and e.errno != errno.EINVAL: + raise self.stdin.close() elif self.stdout: stdout = self.stdout.read() @@ -929,7 +933,11 @@ if self.stdin: if input is not None: - self.stdin.write(input) + try: + self.stdin.write(input) + except IOError as e: + if e.errno != errno.EPIPE: + raise self.stdin.close() if self.stdout: @@ -1290,9 +1298,16 @@ for fd, mode in ready: if mode & select.POLLOUT: chunk = input[input_offset : input_offset + _PIPE_BUF] - input_offset += os.write(fd, chunk) - if input_offset >= len(input): - close_unregister_and_remove(fd) + try: + input_offset += os.write(fd, chunk) + except OSError as e: + if e.errno == errno.EPIPE: + close_unregister_and_remove(fd) + else: + raise + else: + if input_offset >= len(input): + close_unregister_and_remove(fd) elif mode & select_POLLIN_POLLPRI: data = os.read(fd, 4096) if not data: @@ -1334,11 +1349,19 @@ if self.stdin in wlist: chunk = input[input_offset : input_offset + _PIPE_BUF] - bytes_written = os.write(self.stdin.fileno(), chunk) - input_offset += bytes_written - if input_offset >= len(input): - self.stdin.close() - write_set.remove(self.stdin) + try: + bytes_written = os.write(self.stdin.fileno(), chunk) + except OSError as e: + if e.errno == errno.EPIPE: + self.stdin.close() + write_set.remove(self.stdin) + else: + raise + else: + input_offset += bytes_written + if input_offset >= len(input): + self.stdin.close() + write_set.remove(self.stdin) if self.stdout in rlist: data = os.read(self.stdout.fileno(), 1024) diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -592,6 +592,25 @@ self.assertFalse(os.path.exists(ofname)) self.assertFalse(os.path.exists(efname)) + def test_communicate_epipe(self): + # Issue 10963: communicate() should hide EPIPE + p = subprocess.Popen([sys.executable, "-c", 'pass'], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + self.addCleanup(p.stdout.close) + self.addCleanup(p.stderr.close) + self.addCleanup(p.stdin.close) + p.communicate(b"x" * 2**20) + + def test_communicate_epipe_only_stdin(self): + # Issue 10963: communicate() should hide EPIPE + p = subprocess.Popen([sys.executable, "-c", 'pass'], + stdin=subprocess.PIPE) + self.addCleanup(p.stdin.close) + time.sleep(2) + p.communicate(b"x" * 2**20) + # # POSIX tests # diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -44,6 +44,8 @@ Library ------- +- Issue #10963: Ensure that subprocess.communicate() never raises EPIPE. + - Issue #11696: Fix ID generation in msilib. - Issue #9696: Fix exception incorrectly raised by xdrlib.Packer.pack_int when -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 5 16:10:23 2011 From: python-checkins at python.org (ross.lagerwall) Date: Tue, 05 Apr 2011 16:10:23 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): Merge with 3.1 Message-ID: http://hg.python.org/cpython/rev/a7363288c8d4 changeset: 69155:a7363288c8d4 branch: 3.2 parent: 69143:8d5ea25d79d0 parent: 69154:158495d49f58 user: Ross Lagerwall date: Tue Apr 05 15:48:47 2011 +0200 summary: Merge with 3.1 files: Lib/subprocess.py | 45 ++++++++++++++++++------ Lib/test/test_subprocess.py | 19 ++++++++++ Misc/NEWS | 2 + Objects/typeslots.inc | 2 +- 4 files changed, 56 insertions(+), 12 deletions(-) diff --git a/Lib/subprocess.py b/Lib/subprocess.py --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -345,6 +345,7 @@ import signal import builtins import warnings +import errno # Exception classes used by this module. class CalledProcessError(Exception): @@ -376,7 +377,6 @@ else: import select _has_poll = hasattr(select, 'poll') - import errno import fcntl import pickle @@ -785,7 +785,11 @@ stderr = None if self.stdin: if input: - self.stdin.write(input) + try: + self.stdin.write(input) + except IOError as e: + if e.errno != errno.EPIPE and e.errno != errno.EINVAL: + raise self.stdin.close() elif self.stdout: stdout = self.stdout.read() @@ -1019,7 +1023,11 @@ if self.stdin: if input is not None: - self.stdin.write(input) + try: + self.stdin.write(input) + except IOError as e: + if e.errno != errno.EPIPE: + raise self.stdin.close() if self.stdout: @@ -1455,9 +1463,16 @@ for fd, mode in ready: if mode & select.POLLOUT: chunk = input[input_offset : input_offset + _PIPE_BUF] - input_offset += os.write(fd, chunk) - if input_offset >= len(input): - close_unregister_and_remove(fd) + try: + input_offset += os.write(fd, chunk) + except OSError as e: + if e.errno == errno.EPIPE: + close_unregister_and_remove(fd) + else: + raise + else: + if input_offset >= len(input): + close_unregister_and_remove(fd) elif mode & select_POLLIN_POLLPRI: data = os.read(fd, 4096) if not data: @@ -1499,11 +1514,19 @@ if self.stdin in wlist: chunk = input[input_offset : input_offset + _PIPE_BUF] - bytes_written = os.write(self.stdin.fileno(), chunk) - input_offset += bytes_written - if input_offset >= len(input): - self.stdin.close() - write_set.remove(self.stdin) + try: + bytes_written = os.write(self.stdin.fileno(), chunk) + except OSError as e: + if e.errno == errno.EPIPE: + self.stdin.close() + write_set.remove(self.stdin) + else: + raise + else: + input_offset += bytes_written + if input_offset >= len(input): + self.stdin.close() + write_set.remove(self.stdin) if self.stdout in rlist: data = os.read(self.stdout.fileno(), 1024) diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -626,6 +626,25 @@ self.assertFalse(os.path.exists(ofname)) self.assertFalse(os.path.exists(efname)) + def test_communicate_epipe(self): + # Issue 10963: communicate() should hide EPIPE + p = subprocess.Popen([sys.executable, "-c", 'pass'], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + self.addCleanup(p.stdout.close) + self.addCleanup(p.stderr.close) + self.addCleanup(p.stdin.close) + p.communicate(b"x" * 2**20) + + def test_communicate_epipe_only_stdin(self): + # Issue 10963: communicate() should hide EPIPE + p = subprocess.Popen([sys.executable, "-c", 'pass'], + stdin=subprocess.PIPE) + self.addCleanup(p.stdin.close) + time.sleep(2) + p.communicate(b"x" * 2**20) + # context manager class _SuppressCoreFiles(object): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -49,6 +49,8 @@ Library ------- +- Issue #10963: Ensure that subprocess.communicate() never raises EPIPE. + - Issue #11746: Fix SSLContext.load_cert_chain() to accept elliptic curve private keys. diff --git a/Objects/typeslots.inc b/Objects/typeslots.inc --- a/Objects/typeslots.inc +++ b/Objects/typeslots.inc @@ -1,4 +1,4 @@ -/* Generated by typeslots.py $Revision: 87806 $ */ +/* Generated by typeslots.py $Revision$ */ 0, 0, offsetof(PyHeapTypeObject, as_mapping.mp_ass_subscript), -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 5 16:10:25 2011 From: python-checkins at python.org (ross.lagerwall) Date: Tue, 05 Apr 2011 16:10:25 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge with 3.2 Message-ID: http://hg.python.org/cpython/rev/c81ad4361c49 changeset: 69156:c81ad4361c49 parent: 69152:3664fc29e867 parent: 69155:a7363288c8d4 user: Ross Lagerwall date: Tue Apr 05 16:07:49 2011 +0200 summary: Merge with 3.2 files: Lib/subprocess.py | 45 ++++++++++++++++++------ Lib/test/test_subprocess.py | 19 ++++++++++ Misc/NEWS | 2 + 3 files changed, 55 insertions(+), 11 deletions(-) diff --git a/Lib/subprocess.py b/Lib/subprocess.py --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -348,6 +348,7 @@ import signal import builtins import warnings +import errno # Exception classes used by this module. class SubprocessError(Exception): pass @@ -396,7 +397,6 @@ else: import select _has_poll = hasattr(select, 'poll') - import errno import fcntl import pickle @@ -826,7 +826,11 @@ stderr = None if self.stdin: if input: - self.stdin.write(input) + try: + self.stdin.write(input) + except IOError as e: + if e.errno != errno.EPIPE and e.errno != errno.EINVAL: + raise self.stdin.close() elif self.stdout: stdout = self.stdout.read() @@ -1104,7 +1108,11 @@ if self.stdin: if input is not None: - self.stdin.write(input) + try: + self.stdin.write(input) + except IOError as e: + if e.errno != errno.EPIPE: + raise self.stdin.close() # Wait for the reader threads, or time out. If we time out, the @@ -1621,9 +1629,16 @@ if mode & select.POLLOUT: chunk = self._input[self._input_offset : self._input_offset + _PIPE_BUF] - self._input_offset += os.write(fd, chunk) - if self._input_offset >= len(self._input): - close_unregister_and_remove(fd) + try: + self._input_offset += os.write(fd, chunk) + except OSError as e: + if e.errno == errno.EPIPE: + close_unregister_and_remove(fd) + else: + raise + else: + if self._input_offset >= len(self._input): + close_unregister_and_remove(fd) elif mode & select_POLLIN_POLLPRI: data = os.read(fd, 4096) if not data: @@ -1691,11 +1706,19 @@ if self.stdin in wlist: chunk = self._input[self._input_offset : self._input_offset + _PIPE_BUF] - bytes_written = os.write(self.stdin.fileno(), chunk) - self._input_offset += bytes_written - if self._input_offset >= len(self._input): - self.stdin.close() - self._write_set.remove(self.stdin) + try: + bytes_written = os.write(self.stdin.fileno(), chunk) + except OSError as e: + if e.errno == errno.EPIPE: + self.stdin.close() + self._write_set.remove(self.stdin) + else: + raise + else: + self._input_offset += bytes_written + if self._input_offset >= len(self._input): + self.stdin.close() + self._write_set.remove(self.stdin) if self.stdout in rlist: data = os.read(self.stdout.fileno(), 1024) diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -720,6 +720,25 @@ self.assertFalse(os.path.exists(ofname)) self.assertFalse(os.path.exists(efname)) + def test_communicate_epipe(self): + # Issue 10963: communicate() should hide EPIPE + p = subprocess.Popen([sys.executable, "-c", 'pass'], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + self.addCleanup(p.stdout.close) + self.addCleanup(p.stderr.close) + self.addCleanup(p.stdin.close) + p.communicate(b"x" * 2**20) + + def test_communicate_epipe_only_stdin(self): + # Issue 10963: communicate() should hide EPIPE + p = subprocess.Popen([sys.executable, "-c", 'pass'], + stdin=subprocess.PIPE) + self.addCleanup(p.stdin.close) + time.sleep(2) + p.communicate(b"x" * 2**20) + # context manager class _SuppressCoreFiles(object): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -94,6 +94,8 @@ Library ------- +- Issue #10963: Ensure that subprocess.communicate() never raises EPIPE. + - Issue #10791: Implement missing method GzipFile.read1(), allowing GzipFile to be wrapped in a TextIOWrapper. Patch by Nadeem Vawda. -- Repository URL: http://hg.python.org/cpython From ezio.melotti at gmail.com Tue Apr 5 16:53:04 2011 From: ezio.melotti at gmail.com (Ezio Melotti) Date: Tue, 05 Apr 2011 17:53:04 +0300 Subject: [Python-checkins] peps: Draft of PEP 399: Pure Python/C Accelerator Module Compatibiilty Requirements In-Reply-To: References: Message-ID: <4D9B2CD0.7060002@gmail.com> Hi, On 05/04/2011 2.37, brett.cannon wrote: > http://hg.python.org/peps/rev/7b9a5b01b479 > changeset: 3855:7b9a5b01b479 > user: Brett Cannon > date: Mon Apr 04 16:37:07 2011 -0700 > summary: > Draft of PEP 399: Pure Python/C Accelerator Module Compatibiilty Requirements > > files: > pep-0399.txt | 205 +++++++++++++++++++++++++++++++++++++++ > 1 files changed, 205 insertions(+), 0 deletions(-) > > > diff --git a/pep-0399.txt b/pep-0399.txt > new file mode 100644 > --- /dev/null > +++ b/pep-0399.txt > @@ -0,0 +1,205 @@ > +PEP: 399 > +Title: Pure Python/C Accelerator Module Compatibiilty Requirements > +Version: $Revision: 88219 $ > +Last-Modified: $Date: 2011-01-27 13:47:00 -0800 (Thu, 27 Jan 2011) $ > +Author: Brett Cannon > +Status: Draft > +Type: Informational > +Content-Type: text/x-rst > +Created: 04-Apr-2011 > +Python-Version: 3.3 > +Post-History: > + > [...] > + > +Any accelerated code must be semantically identical to the pure Python > +implementation. The only time any semantics are allowed to be > +different are when technical details of the VM providing the > +accelerated code prevent matching semantics from being possible, e.g., > +a class being a ``type`` when implemented in C. The semantics > +equivalence requirement also dictates that no public API be provided > +in accelerated code that does not exist in the pure Python code. > +Without this requirement people could accidentally come to rely on a > +detail in the acclerated code which is not made available to other VMs s/acclerated/accelerated/ > +that use the pure Python implementation. To help verify that the > +contract of semantic equivalence is being met, a module must be tested > +both with and without its accelerated code as thoroughly as possible. > + > +As an example, to write tests which exercise both the pure Python and > +C acclerated versions of a module, a basic idiom can be followed:: ditto > + > + import collections.abc > + from test.support import import_fresh_module, run_unittest > + import unittest > + > + c_heapq = import_fresh_module('heapq', fresh=['_heapq']) > + py_heapq = import_fresh_module('heapq', blocked=['_heapq']) > + > + > + class ExampleTest(unittest.TestCase): > [...] > +Copyright > +========= > + > +This document has been placed in the public domain. > + > + > +.. _IronPython: http://ironpython.net/ > +.. _Jython: http://www.jython.org/ > +.. _PyPy: http://pypy.org/ > +.. _C API of Python: http://docs.python.org/py3k/c-api/index.html > +.. _sqlite3: http://docs.python.org/py3k/library/sqlite3.html > Best Regards, Ezio Melotti From python-checkins at python.org Tue Apr 5 18:13:19 2011 From: python-checkins at python.org (antoine.pitrou) Date: Tue, 05 Apr 2011 18:13:19 +0200 Subject: [Python-checkins] cpython (3.1): Try to fix sporadic test_multiprocessing failure Message-ID: http://hg.python.org/cpython/rev/7a1ef59d765b changeset: 69157:7a1ef59d765b branch: 3.1 parent: 69154:158495d49f58 user: Antoine Pitrou date: Tue Apr 05 18:11:33 2011 +0200 summary: Try to fix sporadic test_multiprocessing failure files: Lib/test/test_multiprocessing.py | 12 +++++++++++- 1 files changed, 11 insertions(+), 1 deletions(-) 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 @@ -12,6 +12,7 @@ import sys import os import gc +import errno import signal import array import socket @@ -1277,7 +1278,16 @@ manager.shutdown() manager = QueueManager( address=addr, authkey=authkey, serializer=SERIALIZER) - manager.start() + try: + manager.start() + except IOError as e: + if e.errno != errno.EADDRINUSE: + raise + # Retry after some time, in case the old socket was lingering + # (sporadic failure on buildbots) + time.sleep(1.0) + manager = QueueManager( + address=addr, authkey=authkey, serializer=SERIALIZER) manager.shutdown() # -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 5 18:13:20 2011 From: python-checkins at python.org (antoine.pitrou) Date: Tue, 05 Apr 2011 18:13:20 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): Try to fix sporadic test_multiprocessing failure Message-ID: http://hg.python.org/cpython/rev/8a65e6aff672 changeset: 69158:8a65e6aff672 branch: 3.2 parent: 69155:a7363288c8d4 parent: 69157:7a1ef59d765b user: Antoine Pitrou date: Tue Apr 05 18:12:15 2011 +0200 summary: Try to fix sporadic test_multiprocessing failure files: Lib/test/test_multiprocessing.py | 12 +++++++++++- 1 files changed, 11 insertions(+), 1 deletions(-) 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 @@ -11,6 +11,7 @@ import sys import os import gc +import errno import signal import array import socket @@ -1359,7 +1360,16 @@ manager.shutdown() manager = QueueManager( address=addr, authkey=authkey, serializer=SERIALIZER) - manager.start() + try: + manager.start() + except IOError as e: + if e.errno != errno.EADDRINUSE: + raise + # Retry after some time, in case the old socket was lingering + # (sporadic failure on buildbots) + time.sleep(1.0) + manager = QueueManager( + address=addr, authkey=authkey, serializer=SERIALIZER) manager.shutdown() # -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 5 18:13:24 2011 From: python-checkins at python.org (antoine.pitrou) Date: Tue, 05 Apr 2011 18:13:24 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Try to fix sporadic test_multiprocessing failure Message-ID: http://hg.python.org/cpython/rev/a9371cf1cc61 changeset: 69159:a9371cf1cc61 parent: 69156:c81ad4361c49 parent: 69158:8a65e6aff672 user: Antoine Pitrou date: Tue Apr 05 18:13:06 2011 +0200 summary: Try to fix sporadic test_multiprocessing failure files: Lib/test/test_multiprocessing.py | 12 +++++++++++- 1 files changed, 11 insertions(+), 1 deletions(-) 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 @@ -11,6 +11,7 @@ import sys import os import gc +import errno import signal import array import socket @@ -1371,7 +1372,16 @@ manager.shutdown() manager = QueueManager( address=addr, authkey=authkey, serializer=SERIALIZER) - manager.start() + try: + manager.start() + except IOError as e: + if e.errno != errno.EADDRINUSE: + raise + # Retry after some time, in case the old socket was lingering + # (sporadic failure on buildbots) + time.sleep(1.0) + manager = QueueManager( + address=addr, authkey=authkey, serializer=SERIALIZER) manager.shutdown() # -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 5 19:40:55 2011 From: python-checkins at python.org (ezio.melotti) Date: Tue, 05 Apr 2011 19:40:55 +0200 Subject: [Python-checkins] cpython (2.7): #7311: fix HTMLParser to accept non-ASCII attribute values. Message-ID: http://hg.python.org/cpython/rev/7d4dea76c476 changeset: 69160:7d4dea76c476 branch: 2.7 parent: 69153:c10d55c51d81 user: Ezio Melotti date: Tue Apr 05 20:40:52 2011 +0300 summary: #7311: fix HTMLParser to accept non-ASCII attribute values. files: Lib/HTMLParser.py | 2 +- Lib/test/test_htmlparser.py | 17 +++++++++++++++++ Misc/NEWS | 2 ++ 3 files changed, 20 insertions(+), 1 deletions(-) diff --git a/Lib/HTMLParser.py b/Lib/HTMLParser.py --- a/Lib/HTMLParser.py +++ b/Lib/HTMLParser.py @@ -26,7 +26,7 @@ tagfind = re.compile('[a-zA-Z][-.a-zA-Z0-9:_]*') attrfind = re.compile( r'\s*([a-zA-Z_][-.:a-zA-Z_0-9]*)(\s*=\s*' - r'(\'[^\']*\'|"[^"]*"|[-a-zA-Z0-9./,:;+*%?!&$\(\)_#=~@]*))?') + r'(\'[^\']*\'|"[^"]*"|[^\s"\'=<>`]*))?') locatestarttagend = re.compile(r""" <[a-zA-Z][-.a-zA-Z0-9:_]* # tag name diff --git a/Lib/test/test_htmlparser.py b/Lib/test/test_htmlparser.py --- a/Lib/test/test_htmlparser.py +++ b/Lib/test/test_htmlparser.py @@ -208,6 +208,23 @@ ("starttag", "a", [("href", "mailto:xyz at example.com")]), ]) + def test_attr_nonascii(self): + # see issue 7311 + self._run_check(u"\u4e2d\u6587", [ + ("starttag", "img", [("src", "/foo/bar.png"), + ("alt", u"\u4e2d\u6587")]), + ]) + self._run_check(u"", [ + ("starttag", "a", [("title", u"\u30c6\u30b9\u30c8"), + ("href", u"\u30c6\u30b9\u30c8.html")]), + ]) + self._run_check(u'', [ + ("starttag", "a", [("title", u"\u30c6\u30b9\u30c8"), + ("href", u"\u30c6\u30b9\u30c8.html")]), + ]) + def test_attr_entity_replacement(self): self._run_check("""""", [ ("starttag", "a", [("b", "&><\"'")]), diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -47,6 +47,8 @@ Library ------- +- Issue #7311: fix HTMLParser to accept non-ASCII attribute values. + - Issue #10963: Ensure that subprocess.communicate() never raises EPIPE. - Issue #11662: Make urllib and urllib2 ignore redirections if the -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 5 20:47:51 2011 From: python-checkins at python.org (barry.warsaw) Date: Tue, 05 Apr 2011 20:47:51 +0200 Subject: [Python-checkins] peps: PEP 396. Message-ID: http://hg.python.org/peps/rev/1857fe1e65ab changeset: 3857:1857fe1e65ab parent: 3854:f65beac56930 user: Barry Warsaw date: Tue Apr 05 14:47:18 2011 -0400 summary: PEP 396. files: pep-0396.txt | 311 +++++++++++++++++++++++++++++++++++++++ 1 files changed, 311 insertions(+), 0 deletions(-) diff --git a/pep-0396.txt b/pep-0396.txt new file mode 100644 --- /dev/null +++ b/pep-0396.txt @@ -0,0 +1,311 @@ +PEP: 396 +Title: Module Version Numbers +Version: $Revision: 65628 $ +Last-Modified: $Date: 2008-08-10 09:59:20 -0400 (Sun, 10 Aug 2008) $ +Author: Barry Warsaw +Status: Draft +Type: Informational +Content-Type: text/x-rst +Created: 2011-03-16 +Post-History: + + +Abstract +======== + +Given that it is useful and common to specify version numbers for +Python modules, and given that different ways of doing this have grown +organically within the Python community, it is useful to establish +standard conventions for module authors to adhere to and reference. +This informational PEP describes best practices for Python module +authors who want to define the version number of their Python module. + +Conformance with this PEP is optional, however other Python tools +(such as ``distutils2`` [1]_) may be adapted to use the conventions +defined here. + + +User Stories +============ + +Alice is writing a new module, called ``alice``, which she wants to +share with other Python developers. ``alice`` is a simple module and +lives in one file, ``alice.py``. Alice wants to specify a version +number so that her users can tell which version they are using. +Because her module lives entirely in one file, she wants to add the +version number to that file. + +Bob has written a module called ``bob`` which he has shared with many +users. ``bob.py`` contains a version number for the convenience of +his users. Bob learns about the Cheeseshop [2]_, and adds some simple +packaging using classic distutils so that he can upload *The Bob +Bundle* to the Cheeseshop. Because ``bob.py`` already specifies a +version number which his users can access programmatically, he wants +the same API to continue to work even though his users now get it from +the Cheeseshop. + +Carole maintains several namespace packages, each of which are +independently developed and distributed. In order for her users to +properly specify dependencies on the right versions of her packages, +she specifies the version numbers in the namespace package's +``setup.py`` file. Because Carol wants to have to update one version +number per package, she specifies the version number in her module and +has the ``setup.py`` extract the module version number when she builds +the *sdist* archive. + +David maintains a package in the standard library, and also produces +standalone versions for other versions of Python. The standard +library copy defines the version number in the module, and this same +version number is used for the standalone distributions as well. + + +Rationale +========= + +Python modules, both in the standard library and available from third +parties, have long included version numbers. There are established +de-facto standards for describing version numbers, and many ad-hoc +ways have grown organically over the years. Often, version numbers +can be retrieved from a module programmatically, by importing the +module and inspecting an attribute. Classic Python distutils +``setup()`` functions [3]_ describe a ``version`` argument where the +release's version number can be specified. PEP 8 [4]_ describes the +use of a module attribute called ``__version__`` for recording +"Subversion, CVS, or RCS" version strings using keyword expansion. In +the PEP author's own email archives, the earliest example of the use +of an ``__version__`` module attribute by independent module +developers dates back to 1995. + +Another example of version information is the sqlite3 [5]_ library +with its ``sqlite_version_info``, ``version``, and ``version_info`` +attributes. It may not be immediately obvious which attribute +contains a version number for the module, and which contains a version +number for the underlying SQLite3 library. + +This informational PEP codifies established practice, and recommends +standard ways of describing module version numbers, along with some +use cases for when -- and when *not* -- to include them. Its adoption +by module authors is purely voluntary; packaging tools in the standard +library will provide optional support for the standards defined +herein, and other tools in the Python universe may comply as well. + + +Specification +============= + +#. In general, modules in the standard library SHOULD NOT have version + numbers. They implicitly carry the version number of the Python + release they are included in. + +#. On a case-by-case basis, standard library modules which are also + released in standalone form for other Python versions MAY include a + module version number when included in the standard library, and + SHOULD include a version number when packaged separately. + +#. When a module includes a version number, it SHOULD be available in + the ``__version__`` attribute on that module. + +#. For modules which are also packages, the module namespace SHOULD + include the ``__version__`` attribute. + +#. For modules which live inside a namespace package, the sub-package + name SHOULD include the ``__version__`` attribute. The namespace + module itself SHOULD NOT include its own ``__version__`` attribute. + +#. The ``__version__`` attribute's value SHOULD be a string. + +#. Module version numbers SHOULD conform to the normalized version + format specified in PEP 386 [6]_. + +#. Module version numbers SHOULD NOT contain version control system + supplied revision numbers, or any other semantically different + version numbers (e.g. underlying library version number). + +#. Wherever a ``__version__`` attribute exists, a module MAY also + include a ``__version_info__`` attribute, containing a tuple + representation of the module version number, for easy comparisons. + +#. ``__version_info__`` SHOULD be of the format returned by PEP 386's + ``parse_version()`` function. + +#. The ``version`` attribute in a classic distutils ``setup.py`` + file, or the PEP 345 [7]_ ``Version`` metadata field SHOULD be + derived from the ``__version__`` field, or vice versa. + + +Examples +======== + +Retrieving the version number from a third party package:: + + >>> import bzrlib + >>> bzrlib.__version__ + '2.3.0' + +Retrieving the version number from a standard library package that is +also distributed as a standalone module:: + + >>> import email + >>> email.__version__ + '5.1.0' + +Version numbers for namespace packages:: + + >>> import flufl.i18n + >>> import flufl.enum + >>> import flufl.lock + + >>> print flufl.i18n.__version__ + 1.0.4 + >>> print flufl.enum.__version__ + 3.1 + >>> print flufl.lock.__version__ + 2.1 + + >>> import flufl + >>> flufl.__version__ + Traceback (most recent call last): + File "", line 1, in + AttributeError: 'module' object has no attribute '__version__' + >>> + + +Deriving +======== + +Module version numbers can appear in at least two places, and +sometimes more. For example, in accordance with this PEP, they are +available programmatically on the module's ``__version__`` attribute. +In a classic distutils ``setup.py`` file, the ``setup()`` function +takes a ``version`` argument, while the distutils2 ``setup.cfg`` file +has a ``version`` key. The version number must also get into the PEP +345 metadata, preferably when the *sdist* archive is built. It's +desirable for module authors to only have to specify the version +number once, and have all the other uses derive from this single +definition. + +While there are any number of ways this could be done, this section +describes one possible approach, for each scenario. + +Let's say Elle adds this attribute to her module file ``elle.py``:: + + __version__ = '3.1.1' + + +Classic distutils +----------------- + +In classic distutils, the simplest way to add the version string to +the ``setup()`` function in ``setup.py`` is to do something like +this:: + + from elle import __version__ + setup(name='elle', version=__version__) + +In the PEP author's experience however, this can fail in some cases, +such as when the module uses automatic Python 3 conversion via the +``2to3`` program (because ``setup.py`` is executed by Python 3 before +the ``elle`` module has been converted). + +In that case, it's not much more difficult to write a little code to +parse the ``__version__`` from the file rather than importing it:: + + import re + DEFAULT_VERSION_RE = re.compile(r'(?P\d+\.\d(?:\.\d+)?)') + + def get_version(filename, pattern=None): + if pattern is None: + cre = DEFAULT_VERSION_RE + else: + cre = re.compile(pattern) + with open(filename) as fp: + for line in fp: + if line.startswith('__version__'): + mo = cre.search(line) + assert mo, 'No valid __version__ string found' + return mo.group('version') + raise AssertionError('No __version__ assignment found') + + setup(name='elle', version=get_version('elle.py')) + + +Distutils2 +---------- + +Because the distutils2 style ``setup.cfg`` is declarative, we can't +run any code to extract the ``__version__`` attribute, either via +import or via parsing. This PEP suggests a special key be added to +the ``[metadata]`` section of the ``setup.cfg`` file to indicate "get +the version from this file". Something like this might work:: + + [metadata] + version-from-file: elle.py + +where ``parse`` means to use a parsing method similar to the above, on +the file named after the colon. The exact recipe for doing this will +be discussed in the appropriate distutils2 development forum. + +An alternative is to only define the version number in ``setup.cfg`` +and use the ``pkgutil`` module [8]_ to make it available +programmatically. E.g. in ``elle.py``:: + + from distutils2._backport import pkgutil + __version__ = pkgutil.get_distribution('elle').metadata['version'] + + +PEP 376 metadata +================ + +PEP 376 [9]_ defines a standard for static metadata, but doesn't +describe the process by which this metadata gets created. It is +highly desirable for the derived version information to be placed into +the PEP 376 ``.dist-info`` metadata at build-time rather than +install-time. This way, the metadata will be available for +introspection even when the code is not installed. + + +References +========== + +.. [1] Distutils2 documentation + (http://distutils2.notmyidea.org/) + +.. [2] The Cheeseshop (Python Package Index) + (http://pypi.python.org) + +.. [3] http://docs.python.org/distutils/setupscript.html + +.. [4] PEP 8, Style Guide for Python Code + (http://www.python.org/dev/peps/pep-0008) + +.. [5] sqlite3 module documentation + (http://docs.python.org/library/sqlite3.html) + +.. [6] PEP 386, Changing the version comparison module in Distutils + (http://www.python.org/dev/peps/pep-0386/) + +.. [7] PEP 345, Metadata for Python Software Packages 1.2 + (http://www.python.org/dev/peps/pep-0345/#version) + +.. [8] pkgutil - Package utilities + (http://distutils2.notmyidea.org/library/pkgutil.html) + +.. [9] PEP 376, Database of Installed Python Distributions + (http://www.python.org/dev/peps/pep-0376/) + + +Copyright +========= + +This document has been placed in the public domain. + + + +.. + Local Variables: + mode: indented-text + indent-tabs-mode: nil + sentence-end-double-space: t + fill-column: 70 + coding: utf-8 + End: -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Tue Apr 5 20:47:52 2011 From: python-checkins at python.org (barry.warsaw) Date: Tue, 05 Apr 2011 20:47:52 +0200 Subject: [Python-checkins] peps (merge default -> default): merge Message-ID: http://hg.python.org/peps/rev/fc65dddc2af3 changeset: 3858:fc65dddc2af3 parent: 3857:1857fe1e65ab parent: 3856:359ccf54bc52 user: Barry Warsaw date: Tue Apr 05 14:47:46 2011 -0400 summary: merge files: pep-0399.txt | 205 +++++++++++++++++++++++++++++++++++++++ 1 files changed, 205 insertions(+), 0 deletions(-) diff --git a/pep-0399.txt b/pep-0399.txt new file mode 100644 --- /dev/null +++ b/pep-0399.txt @@ -0,0 +1,205 @@ +PEP: 399 +Title: Pure Python/C Accelerator Module Compatibility Requirements +Version: $Revision: 88219 $ +Last-Modified: $Date: 2011-01-27 13:47:00 -0800 (Thu, 27 Jan 2011) $ +Author: Brett Cannon +Status: Draft +Type: Informational +Content-Type: text/x-rst +Created: 04-Apr-2011 +Python-Version: 3.3 +Post-History: + +Abstract +======== + +The Python standard library under CPython contains various instances +of modules implemented in both pure Python and C. This PEP requires +that in these instances that both the Python and C code *must* be +semantically identical (except in cases where implementation details +of a VM prevents it entirely). It is also required that new C-based +modules lacking a pure Python equivalent implementation get special +permissions to be added to the standard library. + + +Rationale +========= + +Python has grown beyond the CPython virtual machine (VM). IronPython_, +Jython_, and PyPy_ all currently being viable alternatives to the +CPython VM. This VM ecosystem that has sprung up around the Python +programming language has led to Python being used in many different +areas where CPython cannot be used, e.g., Jython allowing Python to be +used in Java applications. + +A problem all of the VMs other than CPython face is handling modules +from the standard library that are implemented in C. Since they do not +typically support the entire `C API of Python`_ they are unable to use +the code used to create the module. Often times this leads these other +VMs to either re-implement the modules in pure Python or in the +programming language used to implement the VM (e.g., in C# for +IronPython). This duplication of effort between CPython, PyPy, Jython, +and IronPython is extremely unfortunate as implementing a module *at +least* in pure Python would help mitigate this duplicate effort. + +The purpose of this PEP is to minimize this duplicate effort by +mandating that all new modules added to Python's standard library +*must* have a pure Python implementation _unless_ special dispensation +is given. This makes sure that a module in the stdlib is available to +all VMs and not just to CPython. + +Re-implementing parts (or all) of a module in C (in the case +of CPython) is still allowed for performance reasons, but any such +accelerated code must semantically match the pure Python equivalent to +prevent divergence. To accomplish this, the pure Python and C code must +be thoroughly tested with the *same* test suite to verify compliance. +This is to prevent users from accidentally relying +on semantics that are specific to the C code and are not reflected in +the pure Python implementation that other VMs rely upon, e.g., in +CPython 3.2.0, ``heapq.heappop()`` raises different exceptions +depending on whether the accelerated C code is used or not:: + + from test.support import import_fresh_module + + c_heapq = import_fresh_module('heapq', fresh=['_heapq']) + py_heapq = import_fresh_module('heapq', blocked=['_heapq']) + + + class Spam: + """Tester class which defines no other magic methods but + __len__().""" + def __len__(self): + return 0 + + + try: + c_heapq.heappop(Spam()) + except TypeError: + # "heap argument must be a list" + pass + + try: + py_heapq.heappop(Spam()) + except AttributeError: + # "'Foo' object has no attribute 'pop'" + pass + +This kind of divergence is a problem for users as they unwittingly +write code that is CPython-specific. This is also an issue for other +VM teams as they have to deal with bug reports from users thinking +that they incorrectly implemented the module when in fact it was +caused by an untested case. + + +Details +======= + +Starting in Python 3.3, any modules added to the standard library must +have a pure Python implementation. This rule can only be ignored if +the Python development team grants a special exemption for the module. +Typically the exemption would be granted only when a module wraps a +specific C-based library (e.g., sqlite3_). In granting an exemption it +will be recognized that the module will most likely be considered +exclusive to CPython and not part of Python's standard library that +other VMs are expected to support. Usage of ``ctypes`` to provide an +API for a C library will continue to be frowned upon as ``ctypes`` +lacks compiler guarantees that C code typically relies upon to prevent +certain errors from occurring (e.g., API changes). + +Even though a pure Python implementation is mandated by this PEP, it +does not preclude the use of a companion acceleration module. If an +acceleration module is provided it is to be named the same as the +module it is accelerating with an underscore attached as a prefix, +e.g., ``_warnings`` for ``warnings``. The common pattern to access +the accelerated code from the pure Python implementation is to import +it with an ``import *``, e.g., ``from _warnings import *``. This is +typically done at the end of the module to allow it to overwrite +specific Python objects with their accelerated equivalents. This kind +of import can also be done before the end of the module when needed, +e.g., an accelerated base class is provided but is then subclassed by +Python code. This PEP does not mandate that pre-existing modules in +the stdlib that lack a pure Python equivalent gain such a module. But +if people do volunteer to provide and maintain a pure Python +equivalent (e.g., the PyPy team volunteering their pure Python +implementation of the ``csv`` module and maintaining it) then such +code will be accepted. + +Any accelerated code must be semantically identical to the pure Python +implementation. The only time any semantics are allowed to be +different are when technical details of the VM providing the +accelerated code prevent matching semantics from being possible, e.g., +a class being a ``type`` when implemented in C. The semantics +equivalence requirement also dictates that no public API be provided +in accelerated code that does not exist in the pure Python code. +Without this requirement people could accidentally come to rely on a +detail in the acclerated code which is not made available to other VMs +that use the pure Python implementation. To help verify that the +contract of semantic equivalence is being met, a module must be tested +both with and without its accelerated code as thoroughly as possible. + +As an example, to write tests which exercise both the pure Python and +C acclerated versions of a module, a basic idiom can be followed:: + + import collections.abc + from test.support import import_fresh_module, run_unittest + import unittest + + c_heapq = import_fresh_module('heapq', fresh=['_heapq']) + py_heapq = import_fresh_module('heapq', blocked=['_heapq']) + + + class ExampleTest(unittest.TestCase): + + def test_heappop_exc_for_non_MutableSequence(self): + # Raise TypeError when heap is not a + # collections.abc.MutableSequence. + class Spam: + """Test class lacking many ABC-required methods + (e.g., pop()).""" + def __len__(self): + return 0 + + heap = Spam() + self.assertFalse(isinstance(heap, + collections.abc.MutableSequence)) + with self.assertRaises(TypeError): + self.heapq.heappop(heap) + + + class AcceleratedExampleTest(ExampleTest): + + """Test using the acclerated code.""" + + heapq = c_heapq + + + class PyExampleTest(ExampleTest): + + """Test with just the pure Python code.""" + + heapq = py_heapq + + + def test_main(): + run_unittest(AcceleratedExampleTest, PyExampleTest) + + + if __name__ == '__main__': + test_main() + +Thoroughness of the test can be verified using coverage measurements +with branching coverage on the pure Python code to verify that all +possible scenarios are tested using (or not using) accelerator code. + + +Copyright +========= + +This document has been placed in the public domain. + + +.. _IronPython: http://ironpython.net/ +.. _Jython: http://www.jython.org/ +.. _PyPy: http://pypy.org/ +.. _C API of Python: http://docs.python.org/py3k/c-api/index.html +.. _sqlite3: http://docs.python.org/py3k/library/sqlite3.html -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Tue Apr 5 20:48:35 2011 From: python-checkins at python.org (barry.warsaw) Date: Tue, 05 Apr 2011 20:48:35 +0200 Subject: [Python-checkins] peps: Added Post-History. Message-ID: http://hg.python.org/peps/rev/6d0808c23ad8 changeset: 3859:6d0808c23ad8 user: Barry Warsaw date: Tue Apr 05 14:48:30 2011 -0400 summary: Added Post-History. files: pep-0396.txt | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/pep-0396.txt b/pep-0396.txt --- a/pep-0396.txt +++ b/pep-0396.txt @@ -7,7 +7,7 @@ Type: Informational Content-Type: text/x-rst Created: 2011-03-16 -Post-History: +Post-History: 2011-04-05 Abstract -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Wed Apr 6 00:23:43 2011 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 06 Apr 2011 00:23:43 +0200 Subject: [Python-checkins] cpython: implement tp_clear Message-ID: http://hg.python.org/cpython/rev/7b5d09343929 changeset: 69161:7b5d09343929 parent: 69159:a9371cf1cc61 user: Benjamin Peterson date: Tue Apr 05 17:25:14 2011 -0500 summary: implement tp_clear files: Modules/_functoolsmodule.c | 11 ++++++++++- 1 files changed, 10 insertions(+), 1 deletions(-) diff --git a/Modules/_functoolsmodule.c b/Modules/_functoolsmodule.c --- a/Modules/_functoolsmodule.c +++ b/Modules/_functoolsmodule.c @@ -355,6 +355,15 @@ return 0; } +static int +keyobject_clear(keyobject *ko) +{ + Py_CLEAR(ko->cmp); + if (ko->object) + Py_CLEAR(ko->object); + return 0; +} + static PyMemberDef keyobject_members[] = { {"obj", T_OBJECT, offsetof(keyobject, object), 0, @@ -392,7 +401,7 @@ Py_TPFLAGS_DEFAULT, /* tp_flags */ 0, /* tp_doc */ (traverseproc)keyobject_traverse, /* tp_traverse */ - 0, /* tp_clear */ + (inquiry)keyobject_clear, /* tp_clear */ keyobject_richcompare, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 6 02:20:05 2011 From: python-checkins at python.org (ned.deily) Date: Wed, 06 Apr 2011 02:20:05 +0200 Subject: [Python-checkins] cpython (2.7): Issue #7108: Fix test_commands to not fail when special attributes ('@' Message-ID: http://hg.python.org/cpython/rev/5616cbce0bee changeset: 69162:5616cbce0bee branch: 2.7 parent: 69160:7d4dea76c476 user: Ned Deily date: Tue Apr 05 17:16:09 2011 -0700 summary: Issue #7108: Fix test_commands to not fail when special attributes ('@' or '.') appear in 'ls -l' output. files: Lib/test/test_commands.py | 6 +++++- Misc/NEWS | 3 +++ 2 files changed, 8 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_commands.py b/Lib/test/test_commands.py --- a/Lib/test/test_commands.py +++ b/Lib/test/test_commands.py @@ -49,8 +49,12 @@ # drwxr-xr-x 15 Joe User My Group 4096 Aug 12 12:50 / # Note that the first case above has a space in the group name # while the second one has a space in both names. + # Special attributes supported: + # + = has ACLs + # @ = has Mac OS X extended attributes + # . = has a SELinux security context pat = r'''d......... # It is a directory. - \+? # It may have ACLs. + [.+@]? # It may have special attributes. \s+\d+ # It has some number of links. [^/]* # Skip user, group, size, and date. /\. # and end with the name of the file. diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -315,6 +315,9 @@ Tests ----- +- Issue #7108: Fix test_commands to not fail when special attributes ('@' + or '.') appear in 'ls -l' output. + - Issue #11490: test_subprocess:test_leaking_fds_on_error no longer gives a false positive if the last directory in the path is inaccessible. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 6 02:44:00 2011 From: python-checkins at python.org (alexander.belopolsky) Date: Wed, 06 Apr 2011 02:44:00 +0200 Subject: [Python-checkins] cpython (3.2): Issue #11576: Fixed timedelta subtraction glitch on big timedelta values Message-ID: http://hg.python.org/cpython/rev/76180cc853b6 changeset: 69163:76180cc853b6 branch: 3.2 parent: 69158:8a65e6aff672 user: Alexander Belopolsky date: Tue Apr 05 20:07:38 2011 -0400 summary: Issue #11576: Fixed timedelta subtraction glitch on big timedelta values files: Lib/datetime.py | 6 +++++- Lib/test/datetimetester.py | 6 ++++++ Modules/_datetimemodule.c | 15 ++++++++------- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/Lib/datetime.py b/Lib/datetime.py --- a/Lib/datetime.py +++ b/Lib/datetime.py @@ -485,7 +485,11 @@ def __sub__(self, other): if isinstance(other, timedelta): - return self + -other + # for CPython compatibility, we cannot use + # our __class__ here, but need a real timedelta + return timedelta(self._days - other._days, + self._seconds - other._seconds, + self._microseconds - other._microseconds) return NotImplemented def __rsub__(self, other): diff --git a/Lib/test/datetimetester.py b/Lib/test/datetimetester.py --- a/Lib/test/datetimetester.py +++ b/Lib/test/datetimetester.py @@ -383,6 +383,12 @@ for i in range(-10, 10): eq((i*us/-3)//us, round(i/-3)) + # Issue #11576 + eq(td(999999999, 86399, 999999) - td(999999999, 86399, 999998), + td(0, 0, 1)) + eq(td(999999999, 1, 1) - td(999999999, 1, 0), + td(0, 0, 1)) + def test_disallowed_computations(self): a = timedelta(42) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -1801,13 +1801,14 @@ if (PyDelta_Check(left) && PyDelta_Check(right)) { /* delta - delta */ - PyObject *minus_right = PyNumber_Negative(right); - if (minus_right) { - result = delta_add(left, minus_right); - Py_DECREF(minus_right); - } - else - result = NULL; + /* The C-level additions can't overflow because of the + * invariant bounds. + */ + int days = GET_TD_DAYS(left) - GET_TD_DAYS(right); + int seconds = GET_TD_SECONDS(left) - GET_TD_SECONDS(right); + int microseconds = GET_TD_MICROSECONDS(left) - + GET_TD_MICROSECONDS(right); + result = new_delta(days, seconds, microseconds, 1); } if (result == Py_NotImplemented) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 6 02:44:01 2011 From: python-checkins at python.org (alexander.belopolsky) Date: Wed, 06 Apr 2011 02:44:01 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Issue #11576: Fixed timedelta subtraction glitch on big timedelta values Message-ID: http://hg.python.org/cpython/rev/d492915cf76d changeset: 69164:d492915cf76d parent: 69161:7b5d09343929 parent: 69163:76180cc853b6 user: Alexander Belopolsky date: Tue Apr 05 20:43:15 2011 -0400 summary: Issue #11576: Fixed timedelta subtraction glitch on big timedelta values files: Lib/datetime.py | 6 +++++- Lib/test/datetimetester.py | 6 ++++++ Modules/_datetimemodule.c | 15 ++++++++------- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/Lib/datetime.py b/Lib/datetime.py --- a/Lib/datetime.py +++ b/Lib/datetime.py @@ -485,7 +485,11 @@ def __sub__(self, other): if isinstance(other, timedelta): - return self + -other + # for CPython compatibility, we cannot use + # our __class__ here, but need a real timedelta + return timedelta(self._days - other._days, + self._seconds - other._seconds, + self._microseconds - other._microseconds) return NotImplemented def __rsub__(self, other): diff --git a/Lib/test/datetimetester.py b/Lib/test/datetimetester.py --- a/Lib/test/datetimetester.py +++ b/Lib/test/datetimetester.py @@ -383,6 +383,12 @@ for i in range(-10, 10): eq((i*us/-3)//us, round(i/-3)) + # Issue #11576 + eq(td(999999999, 86399, 999999) - td(999999999, 86399, 999998), + td(0, 0, 1)) + eq(td(999999999, 1, 1) - td(999999999, 1, 0), + td(0, 0, 1)) + def test_disallowed_computations(self): a = timedelta(42) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -1801,13 +1801,14 @@ if (PyDelta_Check(left) && PyDelta_Check(right)) { /* delta - delta */ - PyObject *minus_right = PyNumber_Negative(right); - if (minus_right) { - result = delta_add(left, minus_right); - Py_DECREF(minus_right); - } - else - result = NULL; + /* The C-level additions can't overflow because of the + * invariant bounds. + */ + int days = GET_TD_DAYS(left) - GET_TD_DAYS(right); + int seconds = GET_TD_SECONDS(left) - GET_TD_SECONDS(right); + int microseconds = GET_TD_MICROSECONDS(left) - + GET_TD_MICROSECONDS(right); + result = new_delta(days, seconds, microseconds, 1); } if (result == Py_NotImplemented) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 6 04:14:27 2011 From: python-checkins at python.org (alexander.belopolsky) Date: Wed, 06 Apr 2011 04:14:27 +0200 Subject: [Python-checkins] cpython (2.7): Issue #11576: Fixed timedelta subtraction glitch on big timedelta values Message-ID: http://hg.python.org/cpython/rev/202a9feb1fd6 changeset: 69165:202a9feb1fd6 branch: 2.7 parent: 69162:5616cbce0bee user: Alexander Belopolsky date: Tue Apr 05 22:12:22 2011 -0400 summary: Issue #11576: Fixed timedelta subtraction glitch on big timedelta values files: Lib/test/test_datetime.py | 7 +++++++ Modules/datetimemodule.c | 15 ++++++++------- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/Lib/test/test_datetime.py b/Lib/test/test_datetime.py --- a/Lib/test/test_datetime.py +++ b/Lib/test/test_datetime.py @@ -231,6 +231,13 @@ eq(a//10, td(0, 7*24*360)) eq(a//3600000, td(0, 0, 7*24*1000)) + # Issue #11576 + eq(td(999999999, 86399, 999999) - td(999999999, 86399, 999998), + td(0, 0, 1)) + eq(td(999999999, 1, 1) - td(999999999, 1, 0), + td(0, 0, 1)) + + def test_disallowed_computations(self): a = timedelta(42) diff --git a/Modules/datetimemodule.c b/Modules/datetimemodule.c --- a/Modules/datetimemodule.c +++ b/Modules/datetimemodule.c @@ -1737,13 +1737,14 @@ if (PyDelta_Check(left) && PyDelta_Check(right)) { /* delta - delta */ - PyObject *minus_right = PyNumber_Negative(right); - if (minus_right) { - result = delta_add(left, minus_right); - Py_DECREF(minus_right); - } - else - result = NULL; + /* The C-level additions can't overflow because of the + * invariant bounds. + */ + int days = GET_TD_DAYS(left) - GET_TD_DAYS(right); + int seconds = GET_TD_SECONDS(left) - GET_TD_SECONDS(right); + int microseconds = GET_TD_MICROSECONDS(left) - + GET_TD_MICROSECONDS(right); + result = new_delta(days, seconds, microseconds, 1); } if (result == Py_NotImplemented) -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Wed Apr 6 04:56:58 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Wed, 06 Apr 2011 04:56:58 +0200 Subject: [Python-checkins] Daily reference leaks (d492915cf76d): sum=0 Message-ID: results for d492915cf76d on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/refloglZqgHa', '-x'] From python-checkins at python.org Wed Apr 6 08:16:34 2011 From: python-checkins at python.org (senthil.kumaran) Date: Wed, 06 Apr 2011 08:16:34 +0200 Subject: [Python-checkins] cpython (3.1): Issue #10762: Guard against invalid/non-supported format string '%f' on Message-ID: http://hg.python.org/cpython/rev/2ca1bc677a60 changeset: 69166:2ca1bc677a60 branch: 3.1 parent: 69157:7a1ef59d765b user: Senthil Kumaran date: Wed Apr 06 12:54:06 2011 +0800 summary: Issue #10762: Guard against invalid/non-supported format string '%f' on Windows. Patch Santoso Wijaya. files: Lib/test/test_time.py | 8 ++++++++ Modules/timemodule.c | 2 +- 2 files changed, 9 insertions(+), 1 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 @@ -2,6 +2,7 @@ import time import unittest import locale +import sys class TimeTestCase(unittest.TestCase): @@ -37,6 +38,13 @@ except ValueError: self.fail('conversion specifier: %r failed.' % format) + # Issue #10762: Guard against invalid/non-supported format string + # so that Python don't crash (Windows crashes when the format string + # input to [w]strftime is not kosher. + if sys.platform.startswith('win'): + with self.assertRaises(ValueError): + time.strftime('%f') + def test_strftime_bounds_checking(self): # Make sure that strftime() checks the bounds of the various parts #of the time tuple (0 is valid for *all* values). diff --git a/Modules/timemodule.c b/Modules/timemodule.c --- a/Modules/timemodule.c +++ b/Modules/timemodule.c @@ -549,7 +549,7 @@ if (outbuf[1]=='#') ++outbuf; /* not documented by python, */ if (outbuf[1]=='\0' || - !wcschr(L"aAbBcdfHIjmMpSUwWxXyYzZ%", outbuf[1])) + !wcschr(L"aAbBcdHIjmMpSUwWxXyYzZ%", outbuf[1])) { PyErr_SetString(PyExc_ValueError, "Invalid format string"); return 0; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 6 08:16:36 2011 From: python-checkins at python.org (senthil.kumaran) Date: Wed, 06 Apr 2011 08:16:36 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): Merge from 3.1 Message-ID: http://hg.python.org/cpython/rev/1accc17055c9 changeset: 69167:1accc17055c9 branch: 3.2 parent: 69163:76180cc853b6 parent: 69166:2ca1bc677a60 user: Senthil Kumaran date: Wed Apr 06 14:11:09 2011 +0800 summary: Merge from 3.1 files: Lib/test/test_time.py | 8 ++++++++ Modules/timemodule.c | 2 +- 2 files changed, 9 insertions(+), 1 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 @@ -3,6 +3,7 @@ import unittest import locale import sysconfig +import sys import warnings class TimeTestCase(unittest.TestCase): @@ -39,6 +40,13 @@ except ValueError: self.fail('conversion specifier: %r failed.' % format) + # Issue #10762: Guard against invalid/non-supported format string + # so that Python don't crash (Windows crashes when the format string + # input to [w]strftime is not kosher. + if sys.platform.startswith('win'): + with self.assertRaises(ValueError): + time.strftime('%f') + def _bounds_checking(self, func=time.strftime): # Make sure that strftime() checks the bounds of the various parts #of the time tuple (0 is valid for *all* values). diff --git a/Modules/timemodule.c b/Modules/timemodule.c --- a/Modules/timemodule.c +++ b/Modules/timemodule.c @@ -512,7 +512,7 @@ if (outbuf[1]=='#') ++outbuf; /* not documented by python, */ if (outbuf[1]=='\0' || - !wcschr(L"aAbBcdfHIjmMpSUwWxXyYzZ%", outbuf[1])) + !wcschr(L"aAbBcdHIjmMpSUwWxXyYzZ%", outbuf[1])) { PyErr_SetString(PyExc_ValueError, "Invalid format string"); return 0; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 6 08:16:37 2011 From: python-checkins at python.org (senthil.kumaran) Date: Wed, 06 Apr 2011 08:16:37 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): merge from 3.2 Message-ID: http://hg.python.org/cpython/rev/dc728ac66c3c changeset: 69168:dc728ac66c3c parent: 69164:d492915cf76d parent: 69167:1accc17055c9 user: Senthil Kumaran date: Wed Apr 06 14:16:08 2011 +0800 summary: merge from 3.2 files: Lib/test/test_time.py | 8 ++++++++ Modules/timemodule.c | 2 +- 2 files changed, 9 insertions(+), 1 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 @@ -3,6 +3,7 @@ import unittest import locale import sysconfig +import sys import warnings class TimeTestCase(unittest.TestCase): @@ -39,6 +40,13 @@ except ValueError: self.fail('conversion specifier: %r failed.' % format) + # Issue #10762: Guard against invalid/non-supported format string + # so that Python don't crash (Windows crashes when the format string + # input to [w]strftime is not kosher. + if sys.platform.startswith('win'): + with self.assertRaises(ValueError): + time.strftime('%f') + def _bounds_checking(self, func=time.strftime): # Make sure that strftime() checks the bounds of the various parts #of the time tuple (0 is valid for *all* values). diff --git a/Modules/timemodule.c b/Modules/timemodule.c --- a/Modules/timemodule.c +++ b/Modules/timemodule.c @@ -512,7 +512,7 @@ if (outbuf[1]=='#') ++outbuf; /* not documented by python, */ if (outbuf[1]=='\0' || - !wcschr(L"aAbBcdfHIjmMpSUwWxXyYzZ%", outbuf[1])) + !wcschr(L"aAbBcdHIjmMpSUwWxXyYzZ%", outbuf[1])) { PyErr_SetString(PyExc_ValueError, "Invalid format string"); return 0; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 6 08:45:33 2011 From: python-checkins at python.org (senthil.kumaran) Date: Wed, 06 Apr 2011 08:45:33 +0200 Subject: [Python-checkins] cpython (2.7): Issue #10762: Guard against invalid/non-supported format string '%f' on Message-ID: http://hg.python.org/cpython/rev/1320f29bcf98 changeset: 69169:1320f29bcf98 branch: 2.7 parent: 69162:5616cbce0bee user: Senthil Kumaran date: Wed Apr 06 14:27:47 2011 +0800 summary: Issue #10762: Guard against invalid/non-supported format string '%f' on Windows. Patch Santoso Wijaya. files: Lib/test/test_time.py | 8 ++++++++ Modules/timemodule.c | 2 +- 2 files changed, 9 insertions(+), 1 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 @@ -1,6 +1,7 @@ from test import test_support import time import unittest +import sys class TimeTestCase(unittest.TestCase): @@ -37,6 +38,13 @@ except ValueError: self.fail('conversion specifier: %r failed.' % format) + # Issue #10762: Guard against invalid/non-supported format string + # so that Python don't crash (Windows crashes when the format string + # input to [w]strftime is not kosher. + if sys.platform.startswith('win'): + with self.assertRaises(ValueError): + time.strftime('%f') + def test_strftime_bounds_checking(self): # Make sure that strftime() checks the bounds of the various parts #of the time tuple (0 is valid for *all* values). diff --git a/Modules/timemodule.c b/Modules/timemodule.c --- a/Modules/timemodule.c +++ b/Modules/timemodule.c @@ -487,7 +487,7 @@ if (outbuf[1]=='#') ++outbuf; /* not documented by python, */ if (outbuf[1]=='\0' || - !strchr("aAbBcdfHIjmMpSUwWxXyYzZ%", outbuf[1])) + !strchr("aAbBcdHIjmMpSUwWxXyYzZ%", outbuf[1])) { PyErr_SetString(PyExc_ValueError, "Invalid format string"); return 0; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 6 08:45:36 2011 From: python-checkins at python.org (senthil.kumaran) Date: Wed, 06 Apr 2011 08:45:36 +0200 Subject: [Python-checkins] cpython (merge 2.7 -> 2.7): hg pull/merge - Changes to accomodate. Message-ID: http://hg.python.org/cpython/rev/da212fa62fea changeset: 69170:da212fa62fea branch: 2.7 parent: 69169:1320f29bcf98 parent: 69165:202a9feb1fd6 user: Senthil Kumaran date: Wed Apr 06 14:41:42 2011 +0800 summary: hg pull/merge - Changes to accomodate. files: Lib/test/test_datetime.py | 7 +++++++ Modules/datetimemodule.c | 15 ++++++++------- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/Lib/test/test_datetime.py b/Lib/test/test_datetime.py --- a/Lib/test/test_datetime.py +++ b/Lib/test/test_datetime.py @@ -231,6 +231,13 @@ eq(a//10, td(0, 7*24*360)) eq(a//3600000, td(0, 0, 7*24*1000)) + # Issue #11576 + eq(td(999999999, 86399, 999999) - td(999999999, 86399, 999998), + td(0, 0, 1)) + eq(td(999999999, 1, 1) - td(999999999, 1, 0), + td(0, 0, 1)) + + def test_disallowed_computations(self): a = timedelta(42) diff --git a/Modules/datetimemodule.c b/Modules/datetimemodule.c --- a/Modules/datetimemodule.c +++ b/Modules/datetimemodule.c @@ -1737,13 +1737,14 @@ if (PyDelta_Check(left) && PyDelta_Check(right)) { /* delta - delta */ - PyObject *minus_right = PyNumber_Negative(right); - if (minus_right) { - result = delta_add(left, minus_right); - Py_DECREF(minus_right); - } - else - result = NULL; + /* The C-level additions can't overflow because of the + * invariant bounds. + */ + int days = GET_TD_DAYS(left) - GET_TD_DAYS(right); + int seconds = GET_TD_SECONDS(left) - GET_TD_SECONDS(right); + int microseconds = GET_TD_MICROSECONDS(left) - + GET_TD_MICROSECONDS(right); + result = new_delta(days, seconds, microseconds, 1); } if (result == Py_NotImplemented) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 6 14:16:41 2011 From: python-checkins at python.org (r.david.murray) Date: Wed, 06 Apr 2011 14:16:41 +0200 Subject: [Python-checkins] cpython (3.2): #11605: don't use set/get_payload in feedparser; they do conversions. Message-ID: http://hg.python.org/cpython/rev/b807cf929e26 changeset: 69171:b807cf929e26 branch: 3.2 parent: 69167:1accc17055c9 user: R David Murray date: Wed Apr 06 08:13:02 2011 -0400 summary: #11605: don't use set/get_payload in feedparser; they do conversions. Really the whole API needs to be gone over to restore the separation of concerns; but that's what email6 is about. files: Lib/email/feedparser.py | 4 +- Lib/email/test/test_email.py | 47 ++++++++++++++++++++++++ Misc/NEWS | 3 + 3 files changed, 52 insertions(+), 2 deletions(-) diff --git a/Lib/email/feedparser.py b/Lib/email/feedparser.py --- a/Lib/email/feedparser.py +++ b/Lib/email/feedparser.py @@ -368,12 +368,12 @@ end = len(mo.group(0)) self._last.epilogue = epilogue[:-end] else: - payload = self._last.get_payload() + payload = self._last._payload if isinstance(payload, str): mo = NLCRE_eol.search(payload) if mo: payload = payload[:-len(mo.group(0))] - self._last.set_payload(payload) + self._last._payload = payload self._input.pop_eof_matcher() self._pop_message() # Set the multipart up for newline cleansing, which will diff --git a/Lib/email/test/test_email.py b/Lib/email/test/test_email.py --- a/Lib/email/test/test_email.py +++ b/Lib/email/test/test_email.py @@ -3168,6 +3168,53 @@ g = email.generator.BytesGenerator(s) g.flatten(msg, linesep='\r\n') self.assertEqual(s.getvalue(), text) + + def test_8bit_multipart(self): + # Issue 11605 + source = textwrap.dedent("""\ + Date: Fri, 18 Mar 2011 17:15:43 +0100 + To: foo at example.com + From: foodwatch-Newsletter + Subject: Aktuelles zu Japan, Klonfleisch und Smiley-System + Message-ID: <76a486bee62b0d200f33dc2ca08220ad at localhost.localdomain> + MIME-Version: 1.0 + Content-Type: multipart/alternative; + boundary="b1_76a486bee62b0d200f33dc2ca08220ad" + + --b1_76a486bee62b0d200f33dc2ca08220ad + Content-Type: text/plain; charset="utf-8" + Content-Transfer-Encoding: 8bit + + Guten Tag, , + + mit gro?er Betroffenheit verfolgen auch wir im foodwatch-Team die + Nachrichten aus Japan. + + + --b1_76a486bee62b0d200f33dc2ca08220ad + Content-Type: text/html; charset="utf-8" + Content-Transfer-Encoding: 8bit + + + + + foodwatch - Newsletter + + +

mit großer Betroffenheit verfolgen auch wir im foodwatch-Team + die Nachrichten aus Japan.

+ + + --b1_76a486bee62b0d200f33dc2ca08220ad-- + + """).encode('utf-8') + msg = email.message_from_bytes(source) + s = BytesIO() + g = email.generator.BytesGenerator(s) + g.flatten(msg) + self.assertEqual(s.getvalue(), source) + maxDiff = None diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -49,6 +49,9 @@ Library ------- +- Issue #11605: email.parser.BytesFeedParser was incorrectly converting multipart + subpararts with an 8bit CTE into unicode instead of preserving the bytes. + - Issue #10963: Ensure that subprocess.communicate() never raises EPIPE. - Issue #11746: Fix SSLContext.load_cert_chain() to accept elliptic curve -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 6 14:16:43 2011 From: python-checkins at python.org (r.david.murray) Date: Wed, 06 Apr 2011 14:16:43 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge #11605: don't use set/get_payload in feedparser; they do conversions. Message-ID: http://hg.python.org/cpython/rev/642c0d6799c5 changeset: 69172:642c0d6799c5 parent: 69168:dc728ac66c3c parent: 69171:b807cf929e26 user: R David Murray date: Wed Apr 06 08:16:13 2011 -0400 summary: Merge #11605: don't use set/get_payload in feedparser; they do conversions. files: Lib/email/feedparser.py | 4 +- Lib/test/test_email/test_email.py | 47 +++++++++++++++++++ Misc/NEWS | 3 + 3 files changed, 52 insertions(+), 2 deletions(-) diff --git a/Lib/email/feedparser.py b/Lib/email/feedparser.py --- a/Lib/email/feedparser.py +++ b/Lib/email/feedparser.py @@ -368,12 +368,12 @@ end = len(mo.group(0)) self._last.epilogue = epilogue[:-end] else: - payload = self._last.get_payload() + payload = self._last._payload if isinstance(payload, str): mo = NLCRE_eol.search(payload) if mo: payload = payload[:-len(mo.group(0))] - self._last.set_payload(payload) + self._last._payload = payload self._input.pop_eof_matcher() self._pop_message() # Set the multipart up for newline cleansing, which will diff --git a/Lib/test/test_email/test_email.py b/Lib/test/test_email/test_email.py --- a/Lib/test/test_email/test_email.py +++ b/Lib/test/test_email/test_email.py @@ -3143,6 +3143,53 @@ g = email.generator.BytesGenerator(s) g.flatten(msg, linesep='\r\n') self.assertEqual(s.getvalue(), text) + + def test_8bit_multipart(self): + # Issue 11605 + source = textwrap.dedent("""\ + Date: Fri, 18 Mar 2011 17:15:43 +0100 + To: foo at example.com + From: foodwatch-Newsletter + Subject: Aktuelles zu Japan, Klonfleisch und Smiley-System + Message-ID: <76a486bee62b0d200f33dc2ca08220ad at localhost.localdomain> + MIME-Version: 1.0 + Content-Type: multipart/alternative; + boundary="b1_76a486bee62b0d200f33dc2ca08220ad" + + --b1_76a486bee62b0d200f33dc2ca08220ad + Content-Type: text/plain; charset="utf-8" + Content-Transfer-Encoding: 8bit + + Guten Tag, , + + mit gro?er Betroffenheit verfolgen auch wir im foodwatch-Team die + Nachrichten aus Japan. + + + --b1_76a486bee62b0d200f33dc2ca08220ad + Content-Type: text/html; charset="utf-8" + Content-Transfer-Encoding: 8bit + + + + + foodwatch - Newsletter + + +

mit großer Betroffenheit verfolgen auch wir im foodwatch-Team + die Nachrichten aus Japan.

+ + + --b1_76a486bee62b0d200f33dc2ca08220ad-- + + """).encode('utf-8') + msg = email.message_from_bytes(source) + s = BytesIO() + g = email.generator.BytesGenerator(s) + g.flatten(msg) + self.assertEqual(s.getvalue(), source) + maxDiff = None diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -94,6 +94,9 @@ Library ------- +- Issue #11605: email.parser.BytesFeedParser was incorrectly converting multipart + subpararts with an 8bit CTE into unicode instead of preserving the bytes. + - Issue #10963: Ensure that subprocess.communicate() never raises EPIPE. - Issue #10791: Implement missing method GzipFile.read1(), allowing GzipFile -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 6 15:52:23 2011 From: python-checkins at python.org (r.david.murray) Date: Wed, 06 Apr 2011 15:52:23 +0200 Subject: [Python-checkins] cpython: #1690608: make formataddr RFC2047 aware. Message-ID: http://hg.python.org/cpython/rev/184ddd9acd5a changeset: 69173:184ddd9acd5a user: R David Murray date: Wed Apr 06 09:35:57 2011 -0400 summary: #1690608: make formataddr RFC2047 aware. Patch by Torsten Becker. files: Doc/library/email.util.rst | 9 +++- Lib/email/utils.py | 28 ++++++++++-- Lib/test/test_email/test_email.py | 40 +++++++++++++++++++ Misc/ACKS | 1 + Misc/NEWS | 4 + 5 files changed, 75 insertions(+), 7 deletions(-) diff --git a/Doc/library/email.util.rst b/Doc/library/email.util.rst --- a/Doc/library/email.util.rst +++ b/Doc/library/email.util.rst @@ -29,13 +29,20 @@ fails, in which case a 2-tuple of ``('', '')`` is returned. -.. function:: formataddr(pair) +.. function:: formataddr(pair, charset='utf-8') The inverse of :meth:`parseaddr`, this takes a 2-tuple of the form ``(realname, email_address)`` and returns the string value suitable for a :mailheader:`To` or :mailheader:`Cc` header. If the first element of *pair* is false, then the second element is returned unmodified. + Optional *charset* is the character set that will be used in the :rfc:`2047` + encoding of the ``realname`` if the ``realname`` contains non-ASCII + characters. Can be an instance of :class:`str` or a + :class:`~email.charset.Charset`. Defaults to ``utf-8``. + + .. versionchanged: 3.3 added the *charset* option + .. function:: getaddresses(fieldvalues) diff --git a/Lib/email/utils.py b/Lib/email/utils.py --- a/Lib/email/utils.py +++ b/Lib/email/utils.py @@ -42,6 +42,7 @@ # Intrapackage imports from email.encoders import _bencode, _qencode +from email.charset import Charset COMMASPACE = ', ' EMPTYSTRING = '' @@ -56,21 +57,36 @@ # Helpers -def formataddr(pair): +def formataddr(pair, charset='utf-8'): """The inverse of parseaddr(), this takes a 2-tuple of the form (realname, email_address) and returns the string value suitable for an RFC 2822 From, To or Cc header. If the first element of pair is false, then the second element is returned unmodified. + + Optional charset if given is the character set that is used to encode + realname in case realname is not ASCII safe. Can be an instance of str or + a Charset-like object which has a header_encode method. Default is + 'utf-8'. """ name, address = pair + # The address MUST (per RFC) be ascii, so throw a UnicodeError if it isn't. + address.encode('ascii') if name: - quotes = '' - if specialsre.search(name): - quotes = '"' - name = escapesre.sub(r'\\\g<0>', name) - return '%s%s%s <%s>' % (quotes, name, quotes, address) + try: + name.encode('ascii') + except UnicodeEncodeError: + if isinstance(charset, str): + charset = Charset(charset) + encoded_name = charset.header_encode(name) + return "%s <%s>" % (encoded_name, address) + else: + quotes = '' + if specialsre.search(name): + quotes = '"' + name = escapesre.sub(r'\\\g<0>', name) + return '%s%s%s <%s>' % (quotes, name, quotes, address) return address diff --git a/Lib/test/test_email/test_email.py b/Lib/test/test_email/test_email.py --- a/Lib/test/test_email/test_email.py +++ b/Lib/test/test_email/test_email.py @@ -2376,6 +2376,46 @@ b = 'person at dom.ain' self.assertEqual(utils.parseaddr(utils.formataddr((a, b))), (a, b)) + def test_quotes_unicode_names(self): + # issue 1690608. email.utils.formataddr() should be rfc2047 aware. + name = "H\u00e4ns W\u00fcrst" + addr = 'person at dom.ain' + utf8_base64 = "=?utf-8?b?SMOkbnMgV8O8cnN0?= " + latin1_quopri = "=?iso-8859-1?q?H=E4ns_W=FCrst?= " + self.assertEqual(utils.formataddr((name, addr)), utf8_base64) + self.assertEqual(utils.formataddr((name, addr), 'iso-8859-1'), + latin1_quopri) + + def test_accepts_any_charset_like_object(self): + # issue 1690608. email.utils.formataddr() should be rfc2047 aware. + name = "H\u00e4ns W\u00fcrst" + addr = 'person at dom.ain' + utf8_base64 = "=?utf-8?b?SMOkbnMgV8O8cnN0?= " + foobar = "FOOBAR" + class CharsetMock: + def header_encode(self, string): + return foobar + mock = CharsetMock() + mock_expected = "%s <%s>" % (foobar, addr) + self.assertEqual(utils.formataddr((name, addr), mock), mock_expected) + self.assertEqual(utils.formataddr((name, addr), Charset('utf-8')), + utf8_base64) + + def test_invalid_charset_like_object_raises_error(self): + # issue 1690608. email.utils.formataddr() should be rfc2047 aware. + name = "H\u00e4ns W\u00fcrst" + addr = 'person at dom.ain' + # A object without a header_encode method: + bad_charset = object() + self.assertRaises(AttributeError, utils.formataddr, (name, addr), + bad_charset) + + def test_unicode_address_raises_error(self): + # issue 1690608. email.utils.formataddr() should be rfc2047 aware. + addr = 'pers\u00f6n at dom.in' + self.assertRaises(UnicodeError, utils.formataddr, (None, addr)) + self.assertRaises(UnicodeError, utils.formataddr, ("Name", addr)) + def test_name_with_dot(self): x = 'John X. Doe ' y = '"John X. Doe" ' diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -979,3 +979,4 @@ Kai Zhu Tarek Ziad? Peter ?strand +Torsten Becker diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -97,6 +97,10 @@ - Issue #11605: email.parser.BytesFeedParser was incorrectly converting multipart subpararts with an 8bit CTE into unicode instead of preserving the bytes. +- Issue #1690608: email.util.formataddr is now RFC2047 aware: it now has a + charset parameter that defaults utf-8 which is used as the charset for RFC + 2047 encoding when the realname contains non-ASCII characters. + - Issue #10963: Ensure that subprocess.communicate() never raises EPIPE. - Issue #10791: Implement missing method GzipFile.read1(), allowing GzipFile -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 6 18:38:26 2011 From: python-checkins at python.org (brett.cannon) Date: Wed, 06 Apr 2011 18:38:26 +0200 Subject: [Python-checkins] peps: Fix some spelling mistakes found by Ezio. Message-ID: http://hg.python.org/peps/rev/69662427c7c5 changeset: 3860:69662427c7c5 user: Brett Cannon date: Wed Apr 06 09:38:21 2011 -0700 summary: Fix some spelling mistakes found by Ezio. files: pep-0399.txt | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pep-0399.txt b/pep-0399.txt --- a/pep-0399.txt +++ b/pep-0399.txt @@ -132,13 +132,13 @@ equivalence requirement also dictates that no public API be provided in accelerated code that does not exist in the pure Python code. Without this requirement people could accidentally come to rely on a -detail in the acclerated code which is not made available to other VMs +detail in the accelerated code which is not made available to other VMs that use the pure Python implementation. To help verify that the contract of semantic equivalence is being met, a module must be tested both with and without its accelerated code as thoroughly as possible. As an example, to write tests which exercise both the pure Python and -C acclerated versions of a module, a basic idiom can be followed:: +C accelerated versions of a module, a basic idiom can be followed:: import collections.abc from test.support import import_fresh_module, run_unittest @@ -168,7 +168,7 @@ class AcceleratedExampleTest(ExampleTest): - """Test using the acclerated code.""" + """Test using the accelerated code.""" heapq = c_heapq -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Wed Apr 6 19:05:59 2011 From: python-checkins at python.org (brett.cannon) Date: Wed, 06 Apr 2011 19:05:59 +0200 Subject: [Python-checkins] peps: Explicitly mention accelerator modules can be a subset of functionality. Message-ID: http://hg.python.org/peps/rev/28f8ebde4dc8 changeset: 3861:28f8ebde4dc8 user: Brett Cannon date: Wed Apr 06 10:05:50 2011 -0700 summary: Explicitly mention accelerator modules can be a subset of functionality. files: pep-0399.txt | 30 ++++++++++++++++-------------- 1 files changed, 16 insertions(+), 14 deletions(-) diff --git a/pep-0399.txt b/pep-0399.txt --- a/pep-0399.txt +++ b/pep-0399.txt @@ -14,12 +14,13 @@ ======== The Python standard library under CPython contains various instances -of modules implemented in both pure Python and C. This PEP requires -that in these instances that both the Python and C code *must* be -semantically identical (except in cases where implementation details -of a VM prevents it entirely). It is also required that new C-based -modules lacking a pure Python equivalent implementation get special -permissions to be added to the standard library. +of modules implemented in both pure Python and C (either entirely or +partially). This PEP requires that in these instances that both the +Python and C code *must* be semantically identical (except in cases +where implementation details of a VM prevents it entirely). It is also +required that new C-based modules lacking a pure Python equivalent +implementation get special permissions to be added to the standard +library. Rationale @@ -33,14 +34,15 @@ used in Java applications. A problem all of the VMs other than CPython face is handling modules -from the standard library that are implemented in C. Since they do not -typically support the entire `C API of Python`_ they are unable to use -the code used to create the module. Often times this leads these other -VMs to either re-implement the modules in pure Python or in the -programming language used to implement the VM (e.g., in C# for -IronPython). This duplication of effort between CPython, PyPy, Jython, -and IronPython is extremely unfortunate as implementing a module *at -least* in pure Python would help mitigate this duplicate effort. +from the standard library that are implemented (to some extent) in C. +Since they do not typically support the entire `C API of Python`_ they +are unable to use the code used to create the module. Often times this +leads these other VMs to either re-implement the modules in pure +Python or in the programming language used to implement the VM +(e.g., in C# for IronPython). This duplication of effort between +CPython, PyPy, Jython, and IronPython is extremely unfortunate as +implementing a module *at least* in pure Python would help mitigate +this duplicate effort. The purpose of this PEP is to minimize this duplicate effort by mandating that all new modules added to Python's standard library -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Wed Apr 6 22:35:36 2011 From: python-checkins at python.org (barry.warsaw) Date: Wed, 06 Apr 2011 22:35:36 +0200 Subject: [Python-checkins] cpython (3.1): Issue 11715: Build extension modules on multiarch Debian and Ubuntu by Message-ID: http://hg.python.org/cpython/rev/7582a78f573b changeset: 69174:7582a78f573b branch: 3.1 parent: 69166:2ca1bc677a60 user: Barry Warsaw date: Wed Apr 06 15:18:12 2011 -0400 summary: Issue 11715: Build extension modules on multiarch Debian and Ubuntu by extending search paths to include multiarch directories. files: setup.py | 21 +++++++++++++++++++++ 1 files changed, 21 insertions(+), 0 deletions(-) diff --git a/setup.py b/setup.py --- a/setup.py +++ b/setup.py @@ -339,10 +339,31 @@ return platform return sys.platform + def add_multiarch_paths(self): + # Debian/Ubuntu multiarch support. + # https://wiki.ubuntu.com/MultiarchSpec + tmpfile = os.path.join(self.build_temp, 'multiarch') + if not os.path.exists(self.build_temp): + os.makedirs(self.build_temp) + ret = os.system( + 'dpkg-architecture -qDEB_HOST_MULTIARCH > %s 2> /dev/null' % + tmpfile) + try: + if ret >> 8 == 0: + with open(tmpfile) as fp: + multiarch_path_component = fp.readline().strip() + add_dir_to_list(self.compiler.library_dirs, + '/usr/lib/' + multiarch_path_component) + add_dir_to_list(self.compiler.include_dirs, + '/usr/include/' + multiarch_path_component) + finally: + os.unlink(tmpfile) + def detect_modules(self): # Ensure that /usr/local is always used add_dir_to_list(self.compiler.library_dirs, '/usr/local/lib') add_dir_to_list(self.compiler.include_dirs, '/usr/local/include') + self.add_multiarch_paths() # Add paths specified in the environment variables LDFLAGS and # CPPFLAGS for header and library files. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 6 22:35:37 2011 From: python-checkins at python.org (barry.warsaw) Date: Wed, 06 Apr 2011 22:35:37 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): Issue 11715: Merge multiarch fix from 3.1 branch. Message-ID: http://hg.python.org/cpython/rev/867937dd2279 changeset: 69175:867937dd2279 branch: 3.2 parent: 69171:b807cf929e26 parent: 69174:7582a78f573b user: Barry Warsaw date: Wed Apr 06 15:19:05 2011 -0400 summary: Issue 11715: Merge multiarch fix from 3.1 branch. files: setup.py | 21 +++++++++++++++++++++ 1 files changed, 21 insertions(+), 0 deletions(-) diff --git a/setup.py b/setup.py --- a/setup.py +++ b/setup.py @@ -370,12 +370,33 @@ return platform return sys.platform + def add_multiarch_paths(self): + # Debian/Ubuntu multiarch support. + # https://wiki.ubuntu.com/MultiarchSpec + tmpfile = os.path.join(self.build_temp, 'multiarch') + if not os.path.exists(self.build_temp): + os.makedirs(self.build_temp) + ret = os.system( + 'dpkg-architecture -qDEB_HOST_MULTIARCH > %s 2> /dev/null' % + tmpfile) + try: + if ret >> 8 == 0: + with open(tmpfile) as fp: + multiarch_path_component = fp.readline().strip() + add_dir_to_list(self.compiler.library_dirs, + '/usr/lib/' + multiarch_path_component) + add_dir_to_list(self.compiler.include_dirs, + '/usr/include/' + multiarch_path_component) + finally: + os.unlink(tmpfile) + def detect_modules(self): # Ensure that /usr/local is always used, but the local build # directories (i.e. '.' and 'Include') must be first. See issue # 10520. add_dir_to_list(self.compiler.library_dirs, '/usr/local/lib') add_dir_to_list(self.compiler.include_dirs, '/usr/local/include') + self.add_multiarch_paths() # Add paths specified in the environment variables LDFLAGS and # CPPFLAGS for header and library files. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 6 22:35:39 2011 From: python-checkins at python.org (barry.warsaw) Date: Wed, 06 Apr 2011 22:35:39 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Issue 11715: Merge multiarch fix from 3.1 branch. Message-ID: http://hg.python.org/cpython/rev/3f00611c3daf changeset: 69176:3f00611c3daf parent: 69173:184ddd9acd5a parent: 69175:867937dd2279 user: Barry Warsaw date: Wed Apr 06 15:19:25 2011 -0400 summary: Issue 11715: Merge multiarch fix from 3.1 branch. files: setup.py | 21 +++++++++++++++++++++ 1 files changed, 21 insertions(+), 0 deletions(-) diff --git a/setup.py b/setup.py --- a/setup.py +++ b/setup.py @@ -370,12 +370,33 @@ return platform return sys.platform + def add_multiarch_paths(self): + # Debian/Ubuntu multiarch support. + # https://wiki.ubuntu.com/MultiarchSpec + tmpfile = os.path.join(self.build_temp, 'multiarch') + if not os.path.exists(self.build_temp): + os.makedirs(self.build_temp) + ret = os.system( + 'dpkg-architecture -qDEB_HOST_MULTIARCH > %s 2> /dev/null' % + tmpfile) + try: + if ret >> 8 == 0: + with open(tmpfile) as fp: + multiarch_path_component = fp.readline().strip() + add_dir_to_list(self.compiler.library_dirs, + '/usr/lib/' + multiarch_path_component) + add_dir_to_list(self.compiler.include_dirs, + '/usr/include/' + multiarch_path_component) + finally: + os.unlink(tmpfile) + def detect_modules(self): # Ensure that /usr/local is always used, but the local build # directories (i.e. '.' and 'Include') must be first. See issue # 10520. add_dir_to_list(self.compiler.library_dirs, '/usr/local/lib') add_dir_to_list(self.compiler.include_dirs, '/usr/local/include') + self.add_multiarch_paths() # Add paths specified in the environment variables LDFLAGS and # CPPFLAGS for header and library files. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 6 22:54:54 2011 From: python-checkins at python.org (antoine.pitrou) Date: Wed, 06 Apr 2011 22:54:54 +0200 Subject: [Python-checkins] cpython (3.2): Issue #11766: increase countdown waiting for a pool of processes to start Message-ID: http://hg.python.org/cpython/rev/c4a514199dba changeset: 69177:c4a514199dba branch: 3.2 parent: 69175:867937dd2279 user: Antoine Pitrou date: Wed Apr 06 22:51:17 2011 +0200 summary: Issue #11766: increase countdown waiting for a pool of processes to start up. Hopefully fixes transient buildbot failures. files: Lib/test/test_multiprocessing.py | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) 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 @@ -1170,7 +1170,8 @@ # Refill the pool p._repopulate_pool() # Wait until all workers are alive - countdown = 5 + # (countdown * DELTA = 5 seconds max startup process time) + countdown = 50 while countdown and not all(w.is_alive() for w in p._pool): countdown -= 1 time.sleep(DELTA) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 6 22:54:57 2011 From: python-checkins at python.org (antoine.pitrou) Date: Wed, 06 Apr 2011 22:54:57 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Issue #11766: increase countdown waiting for a pool of processes to start Message-ID: http://hg.python.org/cpython/rev/3eac8302a448 changeset: 69178:3eac8302a448 parent: 69176:3f00611c3daf parent: 69177:c4a514199dba user: Antoine Pitrou date: Wed Apr 06 22:54:14 2011 +0200 summary: Issue #11766: increase countdown waiting for a pool of processes to start up. Hopefully fixes transient buildbot failures. files: Lib/test/test_multiprocessing.py | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) 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 @@ -1182,7 +1182,8 @@ # Refill the pool p._repopulate_pool() # Wait until all workers are alive - countdown = 5 + # (countdown * DELTA = 5 seconds max startup process time) + countdown = 50 while countdown and not all(w.is_alive() for w in p._pool): countdown -= 1 time.sleep(DELTA) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 6 22:55:42 2011 From: python-checkins at python.org (raymond.hettinger) Date: Wed, 06 Apr 2011 22:55:42 +0200 Subject: [Python-checkins] peps: Add PEP 207 guidance on rich comparisons to PEP 8. Message-ID: http://hg.python.org/peps/rev/64bda015861d changeset: 3862:64bda015861d user: Raymond Hettinger date: Wed Apr 06 13:53:31 2011 -0700 summary: Add PEP 207 guidance on rich comparisons to PEP 8. files: pep-0008.txt | 15 +++++++++++++++ 1 files changed, 15 insertions(+), 0 deletions(-) diff --git a/pep-0008.txt b/pep-0008.txt --- a/pep-0008.txt +++ b/pep-0008.txt @@ -667,6 +667,21 @@ None was set to some other value. The other value might have a type (such as a container) that could be false in a boolean context! + - When implementing ordering operations with rich comparisons, it is best to + implement all six operations (__eq__, __ne__, __lt__, __le__, __gt__, + __ge__) rather than relying on other code to only exercise a particular + comparison. + + To minimize the effort involved, the functools.total_ordering() decorator + provides a tool to generate missing comparison methods. + + PEP 207 indicates that reflexivity rules *are* assumed by Python. Thus, + the interpreter may swap y>x with x=x with x<=y, and may swap the + arguments of x==y and x!=y. The sort() and min() operations are + guaranteed to use the < operator and the max() function uses the > + operator. However, it is best to implement all six operations so that + confusion doesn't arise in other contexts. + - Use class-based exceptions. String exceptions in new code are forbidden, because this language -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Wed Apr 6 23:01:40 2011 From: python-checkins at python.org (antoine.pitrou) Date: Wed, 06 Apr 2011 23:01:40 +0200 Subject: [Python-checkins] cpython (2.7): Issue #11766: increase countdown waiting for a pool of processes to start Message-ID: http://hg.python.org/cpython/rev/2e4cdaffe493 changeset: 69179:2e4cdaffe493 branch: 2.7 parent: 69170:da212fa62fea user: Antoine Pitrou date: Wed Apr 06 22:54:14 2011 +0200 summary: Issue #11766: increase countdown waiting for a pool of processes to start up. Hopefully fixes transient buildbot failures. files: Lib/test/test_multiprocessing.py | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) 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 @@ -1126,7 +1126,8 @@ # Refill the pool p._repopulate_pool() # Wait until all workers are alive - countdown = 5 + # (countdown * DELTA = 5 seconds max startup process time) + countdown = 50 while countdown and not all(w.is_alive() for w in p._pool): countdown -= 1 time.sleep(DELTA) -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Thu Apr 7 04:57:00 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Thu, 07 Apr 2011 04:57:00 +0200 Subject: [Python-checkins] Daily reference leaks (3eac8302a448): sum=0 Message-ID: results for 3eac8302a448 on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/refloguDZg8a', '-x'] From python-checkins at python.org Thu Apr 7 06:16:45 2011 From: python-checkins at python.org (alexander.belopolsky) Date: Thu, 07 Apr 2011 06:16:45 +0200 Subject: [Python-checkins] cpython (3.2): Removed 'or long integer' from bin, oct, and hex docstrings. Message-ID: http://hg.python.org/cpython/rev/d29277949ad6 changeset: 69180:d29277949ad6 branch: 3.2 parent: 69177:c4a514199dba user: Alexander Belopolsky date: Thu Apr 07 00:15:33 2011 -0400 summary: Removed 'or long integer' from bin, oct, and hex docstrings. files: Python/bltinmodule.c | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -307,7 +307,7 @@ PyDoc_STRVAR(bin_doc, "bin(number) -> string\n\ \n\ -Return the binary representation of an integer or long integer."); +Return the binary representation of an integer."); static PyObject * @@ -1192,7 +1192,7 @@ PyDoc_STRVAR(hex_doc, "hex(number) -> string\n\ \n\ -Return the hexadecimal representation of an integer or long integer."); +Return the hexadecimal representation of an integer."); static PyObject * @@ -1380,7 +1380,7 @@ PyDoc_STRVAR(oct_doc, "oct(number) -> string\n\ \n\ -Return the octal representation of an integer or long integer."); +Return the octal representation of an integer."); static PyObject * -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Apr 7 06:16:47 2011 From: python-checkins at python.org (alexander.belopolsky) Date: Thu, 07 Apr 2011 06:16:47 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Removed 'or long integer' from bin, oct, and hex docstrings. Message-ID: http://hg.python.org/cpython/rev/11052e067192 changeset: 69181:11052e067192 parent: 69178:3eac8302a448 parent: 69180:d29277949ad6 user: Alexander Belopolsky date: Thu Apr 07 00:16:22 2011 -0400 summary: Removed 'or long integer' from bin, oct, and hex docstrings. files: Python/bltinmodule.c | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -303,7 +303,7 @@ PyDoc_STRVAR(bin_doc, "bin(number) -> string\n\ \n\ -Return the binary representation of an integer or long integer."); +Return the binary representation of an integer."); static PyObject * @@ -1186,7 +1186,7 @@ PyDoc_STRVAR(hex_doc, "hex(number) -> string\n\ \n\ -Return the hexadecimal representation of an integer or long integer."); +Return the hexadecimal representation of an integer."); static PyObject * @@ -1374,7 +1374,7 @@ PyDoc_STRVAR(oct_doc, "oct(number) -> string\n\ \n\ -Return the octal representation of an integer or long integer."); +Return the octal representation of an integer."); static PyObject * -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Apr 7 11:51:30 2011 From: python-checkins at python.org (victor.stinner) Date: Thu, 07 Apr 2011 11:51:30 +0200 Subject: [Python-checkins] cpython: faulthandler: check PyThreadState_Get() result in dump_tracebacks_later() Message-ID: http://hg.python.org/cpython/rev/7a77a0d9c5b7 changeset: 69182:7a77a0d9c5b7 user: Victor Stinner date: Thu Apr 07 11:37:19 2011 +0200 summary: faulthandler: check PyThreadState_Get() result in dump_tracebacks_later() Cleanup also the code files: Modules/faulthandler.c | 33 +++++++++++++++++++---------- 1 files changed, 21 insertions(+), 12 deletions(-) diff --git a/Modules/faulthandler.c b/Modules/faulthandler.c --- a/Modules/faulthandler.c +++ b/Modules/faulthandler.c @@ -5,6 +5,9 @@ #include #include +/* Allocate at maximum 100 MB of the stack to raise the stack overflow */ +#define STACK_OVERFLOW_MAX_SIZE (100*1024*1024) + #ifdef WITH_THREAD # define FAULTHANDLER_LATER #endif @@ -16,9 +19,6 @@ # define FAULTHANDLER_USER #endif -/* Allocate at maximum 100 MB of the stack to raise the stack overflow */ -#define STACK_OVERFLOW_MAX_SIZE (100*1024*1024) - #define PUTS(fd, str) write(fd, str, strlen(str)) #ifdef HAVE_SIGACTION @@ -451,8 +451,8 @@ } static PyObject* -faulthandler_dump_traceback_later(PyObject *self, - PyObject *args, PyObject *kwargs) +faulthandler_dump_tracebacks_later(PyObject *self, + PyObject *args, PyObject *kwargs) { static char *kwlist[] = {"timeout", "repeat", "file", "exit", NULL}; double timeout; @@ -461,6 +461,7 @@ PyObject *file = NULL; int fd; int exit = 0; + PyThreadState *tstate; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "d|iOi:dump_tracebacks_later", kwlist, @@ -477,6 +478,13 @@ return NULL; } + tstate = PyThreadState_Get(); + if (tstate == NULL) { + PyErr_SetString(PyExc_RuntimeError, + "unable to get the current thread state"); + return NULL; + } + file = faulthandler_get_fileno(file, &fd); if (file == NULL) return NULL; @@ -490,7 +498,7 @@ thread.fd = fd; thread.timeout_ms = timeout_ms; thread.repeat = repeat; - thread.interp = PyThreadState_Get()->interp; + thread.interp = tstate->interp; thread.exit = exit; /* Arm these locks to serve as events when released */ @@ -826,7 +834,7 @@ faulthandler_traverse(PyObject *module, visitproc visit, void *arg) { #ifdef FAULTHANDLER_USER - unsigned int index; + unsigned int signum; #endif #ifdef FAULTHANDLER_LATER @@ -834,8 +842,8 @@ #endif #ifdef FAULTHANDLER_USER if (user_signals != NULL) { - for (index=0; index < NSIG; index++) - Py_VISIT(user_signals[index].file); + for (signum=0; signum < NSIG; signum++) + Py_VISIT(user_signals[signum].file); } #endif Py_VISIT(fatal_error.file); @@ -861,10 +869,11 @@ "if all_threads is True, into file")}, #ifdef FAULTHANDLER_LATER {"dump_tracebacks_later", - (PyCFunction)faulthandler_dump_traceback_later, METH_VARARGS|METH_KEYWORDS, - PyDoc_STR("dump_tracebacks_later(timeout, repeat=False, file=sys.stderr):\n" + (PyCFunction)faulthandler_dump_tracebacks_later, METH_VARARGS|METH_KEYWORDS, + PyDoc_STR("dump_tracebacks_later(timeout, repeat=False, file=sys.stderrn, exit=False):\n" "dump the traceback of all threads in timeout seconds,\n" - "or each timeout seconds if repeat is True.")}, + "or each timeout seconds if repeat is True. If exit is True, " + "call _exit(1) which is not safe.")}, {"cancel_dump_tracebacks_later", (PyCFunction)faulthandler_cancel_dump_tracebacks_later_py, METH_NOARGS, PyDoc_STR("cancel_dump_tracebacks_later():\ncancel the previous call " -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Apr 7 11:51:31 2011 From: python-checkins at python.org (victor.stinner) Date: Thu, 07 Apr 2011 11:51:31 +0200 Subject: [Python-checkins] cpython: faulthandler: we don't use (or need) SA_SIGINFO flag of sigaction() Message-ID: http://hg.python.org/cpython/rev/eef9ab5e50db changeset: 69183:eef9ab5e50db user: Victor Stinner date: Thu Apr 07 11:39:03 2011 +0200 summary: faulthandler: we don't use (or need) SA_SIGINFO flag of sigaction() files: Modules/faulthandler.c | 9 ++------- 1 files changed, 2 insertions(+), 7 deletions(-) diff --git a/Modules/faulthandler.c b/Modules/faulthandler.c --- a/Modules/faulthandler.c +++ b/Modules/faulthandler.c @@ -218,12 +218,7 @@ This function is signal safe and should only call signal safe functions. */ static void -faulthandler_fatal_error( - int signum -#ifdef HAVE_SIGACTION - , siginfo_t *siginfo, void *ucontext -#endif -) +faulthandler_fatal_error(int signum) { const int fd = fatal_error.fd; unsigned int i; @@ -320,7 +315,7 @@ for (i=0; i < faulthandler_nsignals; i++) { handler = &faulthandler_handlers[i]; #ifdef HAVE_SIGACTION - action.sa_sigaction = faulthandler_fatal_error; + action.sa_handler = faulthandler_fatal_error; sigemptyset(&action.sa_mask); /* Do not prevent the signal from being received from within its own signal handler */ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Apr 7 11:51:32 2011 From: python-checkins at python.org (victor.stinner) Date: Thu, 07 Apr 2011 11:51:32 +0200 Subject: [Python-checkins] cpython: faulthandler: fix compilating without threads Message-ID: http://hg.python.org/cpython/rev/6adbf5f3dafb changeset: 69184:6adbf5f3dafb user: Victor Stinner date: Thu Apr 07 11:50:25 2011 +0200 summary: faulthandler: fix compilating without threads files: Lib/test/test_faulthandler.py | 7 +++++++ Modules/faulthandler.c | 8 ++++++++ 2 files changed, 15 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_faulthandler.py b/Lib/test/test_faulthandler.py --- a/Lib/test/test_faulthandler.py +++ b/Lib/test/test_faulthandler.py @@ -8,6 +8,12 @@ import tempfile import unittest +try: + import threading + HAVE_THREADS = True +except ImportError: + HAVE_THREADS = False + TIMEOUT = 0.5 try: @@ -279,6 +285,7 @@ with temporary_filename() as filename: self.check_dump_traceback(filename) + @unittest.skipIf(not HAVE_THREADS, 'need threads') def check_dump_traceback_threads(self, filename): """ Call explicitly dump_traceback(all_threads=True) and check the output. diff --git a/Modules/faulthandler.c b/Modules/faulthandler.c --- a/Modules/faulthandler.c +++ b/Modules/faulthandler.c @@ -250,6 +250,7 @@ PUTS(fd, handler->name); PUTS(fd, "\n\n"); +#ifdef WITH_THREAD /* SIGSEGV, SIGFPE, SIGABRT, SIGBUS and SIGILL are synchronous signals and so are delivered to the thread that caused the fault. Get the Python thread state of the current thread. @@ -259,6 +260,9 @@ used. Read the thread local storage (TLS) instead: call PyGILState_GetThisThreadState(). */ tstate = PyGILState_GetThisThreadState(); +#else + tstate = PyThreadState_Get(); +#endif if (tstate == NULL) return; @@ -540,10 +544,14 @@ if (!user->enabled) return; +#ifdef WITH_THREAD /* PyThreadState_Get() doesn't give the state of the current thread if the thread doesn't hold the GIL. Read the thread local storage (TLS) instead: call PyGILState_GetThisThreadState(). */ tstate = PyGILState_GetThisThreadState(); +#else + tstate = PyThreadState_Get(); +#endif if (user->all_threads) _Py_DumpTracebackThreads(user->fd, user->interp, tstate); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Apr 7 16:48:41 2011 From: python-checkins at python.org (barry.warsaw) Date: Thu, 07 Apr 2011 16:48:41 +0200 Subject: [Python-checkins] cpython (3.1): Refinement by Stefan Krah (see issue 11715, msg133194) to exit early if the Message-ID: http://hg.python.org/cpython/rev/c8738114b962 changeset: 69185:c8738114b962 branch: 3.1 parent: 69174:7582a78f573b user: Barry Warsaw date: Thu Apr 07 10:40:36 2011 -0400 summary: Refinement by Stefan Krah (see issue 11715, msg133194) to exit early if the dpkg-architecture command is not found on $PATH. This should fix the failures on FreeBSD and Solaris, which do not create the target file via I/O redirection if the command isn't found (unlike Linux and OS X which do). files: setup.py | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/setup.py b/setup.py --- a/setup.py +++ b/setup.py @@ -342,6 +342,8 @@ def add_multiarch_paths(self): # Debian/Ubuntu multiarch support. # https://wiki.ubuntu.com/MultiarchSpec + if not find_executable('dpkg-architecture'): + return tmpfile = os.path.join(self.build_temp, 'multiarch') if not os.path.exists(self.build_temp): os.makedirs(self.build_temp) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Apr 7 16:48:41 2011 From: python-checkins at python.org (barry.warsaw) Date: Thu, 07 Apr 2011 16:48:41 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): Refinement by Stefan Krah (see issue 11715, msg133194) to exit early if the Message-ID: http://hg.python.org/cpython/rev/3d7c9b38fbfd changeset: 69186:3d7c9b38fbfd branch: 3.2 parent: 69180:d29277949ad6 parent: 69185:c8738114b962 user: Barry Warsaw date: Thu Apr 07 10:45:07 2011 -0400 summary: Refinement by Stefan Krah (see issue 11715, msg133194) to exit early if the dpkg-architecture command is not found on $PATH. This should fix the failures on FreeBSD and Solaris, which do not create the target file via I/O redirection if the command isn't found (unlike Linux and OS X which do). files: setup.py | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/setup.py b/setup.py --- a/setup.py +++ b/setup.py @@ -373,6 +373,8 @@ def add_multiarch_paths(self): # Debian/Ubuntu multiarch support. # https://wiki.ubuntu.com/MultiarchSpec + if not find_executable('dpkg-architecture'): + return tmpfile = os.path.join(self.build_temp, 'multiarch') if not os.path.exists(self.build_temp): os.makedirs(self.build_temp) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Apr 7 16:48:43 2011 From: python-checkins at python.org (barry.warsaw) Date: Thu, 07 Apr 2011 16:48:43 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Refinement by Stefan Krah (see issue 11715, msg133194) to exit early if the Message-ID: http://hg.python.org/cpython/rev/bbfc65d05588 changeset: 69187:bbfc65d05588 parent: 69184:6adbf5f3dafb parent: 69186:3d7c9b38fbfd user: Barry Warsaw date: Thu Apr 07 10:48:29 2011 -0400 summary: Refinement by Stefan Krah (see issue 11715, msg133194) to exit early if the dpkg-architecture command is not found on $PATH. This should fix the failures on FreeBSD and Solaris, which do not create the target file via I/O redirection if the command isn't found (unlike Linux and OS X which do). files: setup.py | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/setup.py b/setup.py --- a/setup.py +++ b/setup.py @@ -373,6 +373,8 @@ def add_multiarch_paths(self): # Debian/Ubuntu multiarch support. # https://wiki.ubuntu.com/MultiarchSpec + if not find_executable('dpkg-architecture'): + return tmpfile = os.path.join(self.build_temp, 'multiarch') if not os.path.exists(self.build_temp): os.makedirs(self.build_temp) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Apr 7 17:28:50 2011 From: python-checkins at python.org (barry.warsaw) Date: Thu, 07 Apr 2011 17:28:50 +0200 Subject: [Python-checkins] cpython (2.7): Backport for Python 2.7 of issue 11715 support for building Python on Message-ID: http://hg.python.org/cpython/rev/bd0f73a9538e changeset: 69188:bd0f73a9538e branch: 2.7 parent: 69179:2e4cdaffe493 user: Barry Warsaw date: Thu Apr 07 11:28:11 2011 -0400 summary: Backport for Python 2.7 of issue 11715 support for building Python on multiarch Debian/Ubuntu. files: setup.py | 23 +++++++++++++++++++++++ 1 files changed, 23 insertions(+), 0 deletions(-) diff --git a/setup.py b/setup.py --- a/setup.py +++ b/setup.py @@ -345,10 +345,33 @@ return platform return sys.platform + def add_multiarch_paths(self): + # Debian/Ubuntu multiarch support. + # https://wiki.ubuntu.com/MultiarchSpec + if not find_executable('dpkg-architecture'): + return + tmpfile = os.path.join(self.build_temp, 'multiarch') + if not os.path.exists(self.build_temp): + os.makedirs(self.build_temp) + ret = os.system( + 'dpkg-architecture -qDEB_HOST_MULTIARCH > %s 2> /dev/null' % + tmpfile) + try: + if ret >> 8 == 0: + with open(tmpfile) as fp: + multiarch_path_component = fp.readline().strip() + add_dir_to_list(self.compiler.library_dirs, + '/usr/lib/' + multiarch_path_component) + add_dir_to_list(self.compiler.include_dirs, + '/usr/include/' + multiarch_path_component) + finally: + os.unlink(tmpfile) + def detect_modules(self): # Ensure that /usr/local is always used add_dir_to_list(self.compiler.library_dirs, '/usr/local/lib') add_dir_to_list(self.compiler.include_dirs, '/usr/local/include') + self.add_multiarch_paths() # Add paths specified in the environment variables LDFLAGS and # CPPFLAGS for header and library files. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Apr 7 21:27:23 2011 From: python-checkins at python.org (ezio.melotti) Date: Thu, 07 Apr 2011 21:27:23 +0200 Subject: [Python-checkins] cpython (3.2): #7311: fix html.parser to accept non-ASCII attribute values. Message-ID: http://hg.python.org/cpython/rev/225400cb6e84 changeset: 69189:225400cb6e84 branch: 3.2 parent: 69186:3d7c9b38fbfd user: Ezio Melotti date: Thu Apr 07 22:03:31 2011 +0300 summary: #7311: fix html.parser to accept non-ASCII attribute values. files: Lib/html/parser.py | 2 +- Lib/test/test_htmlparser.py | 17 +++++++++++++++++ Misc/NEWS | 2 ++ 3 files changed, 20 insertions(+), 1 deletions(-) diff --git a/Lib/html/parser.py b/Lib/html/parser.py --- a/Lib/html/parser.py +++ b/Lib/html/parser.py @@ -28,7 +28,7 @@ # make it correctly strict without breaking backward compatibility. attrfind = re.compile( r'\s*([a-zA-Z_][-.:a-zA-Z_0-9]*)(\s*=\s*' - r'(\'[^\']*\'|"[^"]*"|[-a-zA-Z0-9./,:;+*%?!&$\(\)_#=~@]*))?') + r'(\'[^\']*\'|"[^"]*"|[^\s"\'=<>`]*))?') attrfind_tolerant = re.compile( r'\s*([a-zA-Z_][-.:a-zA-Z_0-9]*)(\s*=\s*' r'(\'[^\']*\'|"[^"]*"|[^>\s]*))?') diff --git a/Lib/test/test_htmlparser.py b/Lib/test/test_htmlparser.py --- a/Lib/test/test_htmlparser.py +++ b/Lib/test/test_htmlparser.py @@ -217,6 +217,23 @@ ("starttag", "a", [("href", "mailto:xyz at example.com")]), ]) + def test_attr_nonascii(self): + # see issue 7311 + self._run_check("\u4e2d\u6587", [ + ("starttag", "img", [("src", "/foo/bar.png"), + ("alt", "\u4e2d\u6587")]), + ]) + self._run_check("
", [ + ("starttag", "a", [("title", "\u30c6\u30b9\u30c8"), + ("href", "\u30c6\u30b9\u30c8.html")]), + ]) + self._run_check('', [ + ("starttag", "a", [("title", "\u30c6\u30b9\u30c8"), + ("href", "\u30c6\u30b9\u30c8.html")]), + ]) + def test_attr_entity_replacement(self): self._run_check("""""", [ ("starttag", "a", [("b", "&><\"'")]), diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -49,6 +49,8 @@ Library ------- +- Issue #7311: fix html.parser to accept non-ASCII attribute values. + - Issue #11605: email.parser.BytesFeedParser was incorrectly converting multipart subpararts with an 8bit CTE into unicode instead of preserving the bytes. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Apr 7 21:27:24 2011 From: python-checkins at python.org (ezio.melotti) Date: Thu, 07 Apr 2011 21:27:24 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): #7311: merge with 3.2. Message-ID: http://hg.python.org/cpython/rev/a1dea7cde58f changeset: 69190:a1dea7cde58f parent: 69187:bbfc65d05588 parent: 69189:225400cb6e84 user: Ezio Melotti date: Thu Apr 07 22:27:44 2011 +0300 summary: #7311: merge with 3.2. files: Lib/html/parser.py | 2 +- Lib/test/test_htmlparser.py | 17 +++++++++++++++++ Misc/NEWS | 2 ++ 3 files changed, 20 insertions(+), 1 deletions(-) diff --git a/Lib/html/parser.py b/Lib/html/parser.py --- a/Lib/html/parser.py +++ b/Lib/html/parser.py @@ -28,7 +28,7 @@ # make it correctly strict without breaking backward compatibility. attrfind = re.compile( r'\s*([a-zA-Z_][-.:a-zA-Z_0-9]*)(\s*=\s*' - r'(\'[^\']*\'|"[^"]*"|[-a-zA-Z0-9./,:;+*%?!&$\(\)_#=~@]*))?') + r'(\'[^\']*\'|"[^"]*"|[^\s"\'=<>`]*))?') attrfind_tolerant = re.compile( r'\s*([a-zA-Z_][-.:a-zA-Z_0-9]*)(\s*=\s*' r'(\'[^\']*\'|"[^"]*"|[^>\s]*))?') diff --git a/Lib/test/test_htmlparser.py b/Lib/test/test_htmlparser.py --- a/Lib/test/test_htmlparser.py +++ b/Lib/test/test_htmlparser.py @@ -217,6 +217,23 @@ ("starttag", "a", [("href", "mailto:xyz at example.com")]), ]) + def test_attr_nonascii(self): + # see issue 7311 + self._run_check("\u4e2d\u6587", [ + ("starttag", "img", [("src", "/foo/bar.png"), + ("alt", "\u4e2d\u6587")]), + ]) + self._run_check("", [ + ("starttag", "a", [("title", "\u30c6\u30b9\u30c8"), + ("href", "\u30c6\u30b9\u30c8.html")]), + ]) + self._run_check('', [ + ("starttag", "a", [("title", "\u30c6\u30b9\u30c8"), + ("href", "\u30c6\u30b9\u30c8.html")]), + ]) + def test_attr_entity_replacement(self): self._run_check("""""", [ ("starttag", "a", [("b", "&><\"'")]), diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -94,6 +94,8 @@ Library ------- +- Issue #7311: fix html.parser to accept non-ASCII attribute values. + - Issue #11605: email.parser.BytesFeedParser was incorrectly converting multipart subpararts with an 8bit CTE into unicode instead of preserving the bytes. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Apr 7 23:22:32 2011 From: python-checkins at python.org (antoine.pitrou) Date: Thu, 07 Apr 2011 23:22:32 +0200 Subject: [Python-checkins] cpython: Fix faulthandler timeout to avoid breaking buildbots Message-ID: http://hg.python.org/cpython/rev/567cbddf8678 changeset: 69191:567cbddf8678 user: Antoine Pitrou date: Thu Apr 07 23:22:28 2011 +0200 summary: Fix faulthandler timeout to avoid breaking buildbots files: Lib/test/regrtest.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -240,7 +240,7 @@ findleaks=False, use_resources=None, trace=False, coverdir='coverage', runleaks=False, huntrleaks=False, verbose2=False, print_slow=False, random_seed=None, use_mp=None, verbose3=False, forever=False, - header=False, timeout=30*60): + header=False, timeout=60*60): """Execute a test suite. This also parses command-line options and modifies its behavior -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 8 00:30:58 2011 From: python-checkins at python.org (brian.quinlan) Date: Fri, 08 Apr 2011 00:30:58 +0200 Subject: [Python-checkins] cpython: Issue #11777: Executor.map does not submit futures until iter.next() is called Message-ID: http://hg.python.org/cpython/rev/126353bc7e94 changeset: 69192:126353bc7e94 parent: 69181:11052e067192 user: Brian Quinlan date: Fri Apr 08 08:19:33 2011 +1000 summary: Issue #11777: Executor.map does not submit futures until iter.next() is called files: Lib/concurrent/futures/_base.py | 22 ++++++++++------ Lib/test/test_concurrent_futures.py | 10 ++++++- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/Lib/concurrent/futures/_base.py b/Lib/concurrent/futures/_base.py --- a/Lib/concurrent/futures/_base.py +++ b/Lib/concurrent/futures/_base.py @@ -536,15 +536,19 @@ fs = [self.submit(fn, *args) for args in zip(*iterables)] - try: - for future in fs: - if timeout is None: - yield future.result() - else: - yield future.result(end_time - time.time()) - finally: - for future in fs: - future.cancel() + # Yield must be hidden in closure so that the futures are submitted + # before the first iterator value is required. + def result_iterator(): + try: + for future in fs: + if timeout is None: + yield future.result() + else: + yield future.result(end_time - time.time()) + finally: + for future in fs: + future.cancel() + return result_iterator() def shutdown(self, wait=True): """Clean-up the resources associated with the Executor. diff --git a/Lib/test/test_concurrent_futures.py b/Lib/test/test_concurrent_futures.py --- a/Lib/test/test_concurrent_futures.py +++ b/Lib/test/test_concurrent_futures.py @@ -369,7 +369,15 @@ class ThreadPoolExecutorTest(ThreadPoolMixin, ExecutorTest): - pass + def test_map_submits_without_iteration(self): + """Tests verifying issue 11777.""" + finished = [] + def record_finished(n): + finished.append(n) + + self.executor.map(record_finished, range(10)) + self.executor.shutdown(wait=True) + self.assertCountEqual(finished, range(10)) class ProcessPoolExecutorTest(ProcessPoolMixin, ExecutorTest): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 8 00:30:59 2011 From: python-checkins at python.org (brian.quinlan) Date: Fri, 08 Apr 2011 00:30:59 +0200 Subject: [Python-checkins] cpython (merge default -> default): Merge to tip. Message-ID: http://hg.python.org/cpython/rev/9ddba521c3aa changeset: 69193:9ddba521c3aa parent: 69192:126353bc7e94 parent: 69191:567cbddf8678 user: Brian Quinlan date: Fri Apr 08 08:30:41 2011 +1000 summary: Merge to tip. files: Lib/html/parser.py | 2 +- Lib/test/regrtest.py | 2 +- Lib/test/test_faulthandler.py | 7 +++ Lib/test/test_htmlparser.py | 17 +++++++ Misc/NEWS | 2 + Modules/faulthandler.c | 50 ++++++++++++++-------- setup.py | 2 + 7 files changed, 61 insertions(+), 21 deletions(-) diff --git a/Lib/html/parser.py b/Lib/html/parser.py --- a/Lib/html/parser.py +++ b/Lib/html/parser.py @@ -28,7 +28,7 @@ # make it correctly strict without breaking backward compatibility. attrfind = re.compile( r'\s*([a-zA-Z_][-.:a-zA-Z_0-9]*)(\s*=\s*' - r'(\'[^\']*\'|"[^"]*"|[-a-zA-Z0-9./,:;+*%?!&$\(\)_#=~@]*))?') + r'(\'[^\']*\'|"[^"]*"|[^\s"\'=<>`]*))?') attrfind_tolerant = re.compile( r'\s*([a-zA-Z_][-.:a-zA-Z_0-9]*)(\s*=\s*' r'(\'[^\']*\'|"[^"]*"|[^>\s]*))?') diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -240,7 +240,7 @@ findleaks=False, use_resources=None, trace=False, coverdir='coverage', runleaks=False, huntrleaks=False, verbose2=False, print_slow=False, random_seed=None, use_mp=None, verbose3=False, forever=False, - header=False, timeout=30*60): + header=False, timeout=60*60): """Execute a test suite. This also parses command-line options and modifies its behavior diff --git a/Lib/test/test_faulthandler.py b/Lib/test/test_faulthandler.py --- a/Lib/test/test_faulthandler.py +++ b/Lib/test/test_faulthandler.py @@ -8,6 +8,12 @@ import tempfile import unittest +try: + import threading + HAVE_THREADS = True +except ImportError: + HAVE_THREADS = False + TIMEOUT = 0.5 try: @@ -279,6 +285,7 @@ with temporary_filename() as filename: self.check_dump_traceback(filename) + @unittest.skipIf(not HAVE_THREADS, 'need threads') def check_dump_traceback_threads(self, filename): """ Call explicitly dump_traceback(all_threads=True) and check the output. diff --git a/Lib/test/test_htmlparser.py b/Lib/test/test_htmlparser.py --- a/Lib/test/test_htmlparser.py +++ b/Lib/test/test_htmlparser.py @@ -217,6 +217,23 @@ ("starttag", "a", [("href", "mailto:xyz at example.com")]), ]) + def test_attr_nonascii(self): + # see issue 7311 + self._run_check("\u4e2d\u6587", [ + ("starttag", "img", [("src", "/foo/bar.png"), + ("alt", "\u4e2d\u6587")]), + ]) + self._run_check("", [ + ("starttag", "a", [("title", "\u30c6\u30b9\u30c8"), + ("href", "\u30c6\u30b9\u30c8.html")]), + ]) + self._run_check('', [ + ("starttag", "a", [("title", "\u30c6\u30b9\u30c8"), + ("href", "\u30c6\u30b9\u30c8.html")]), + ]) + def test_attr_entity_replacement(self): self._run_check("""""", [ ("starttag", "a", [("b", "&><\"'")]), diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -94,6 +94,8 @@ Library ------- +- Issue #7311: fix html.parser to accept non-ASCII attribute values. + - Issue #11605: email.parser.BytesFeedParser was incorrectly converting multipart subpararts with an 8bit CTE into unicode instead of preserving the bytes. diff --git a/Modules/faulthandler.c b/Modules/faulthandler.c --- a/Modules/faulthandler.c +++ b/Modules/faulthandler.c @@ -5,6 +5,9 @@ #include #include +/* Allocate at maximum 100 MB of the stack to raise the stack overflow */ +#define STACK_OVERFLOW_MAX_SIZE (100*1024*1024) + #ifdef WITH_THREAD # define FAULTHANDLER_LATER #endif @@ -16,9 +19,6 @@ # define FAULTHANDLER_USER #endif -/* Allocate at maximum 100 MB of the stack to raise the stack overflow */ -#define STACK_OVERFLOW_MAX_SIZE (100*1024*1024) - #define PUTS(fd, str) write(fd, str, strlen(str)) #ifdef HAVE_SIGACTION @@ -218,12 +218,7 @@ This function is signal safe and should only call signal safe functions. */ static void -faulthandler_fatal_error( - int signum -#ifdef HAVE_SIGACTION - , siginfo_t *siginfo, void *ucontext -#endif -) +faulthandler_fatal_error(int signum) { const int fd = fatal_error.fd; unsigned int i; @@ -255,6 +250,7 @@ PUTS(fd, handler->name); PUTS(fd, "\n\n"); +#ifdef WITH_THREAD /* SIGSEGV, SIGFPE, SIGABRT, SIGBUS and SIGILL are synchronous signals and so are delivered to the thread that caused the fault. Get the Python thread state of the current thread. @@ -264,6 +260,9 @@ used. Read the thread local storage (TLS) instead: call PyGILState_GetThisThreadState(). */ tstate = PyGILState_GetThisThreadState(); +#else + tstate = PyThreadState_Get(); +#endif if (tstate == NULL) return; @@ -320,7 +319,7 @@ for (i=0; i < faulthandler_nsignals; i++) { handler = &faulthandler_handlers[i]; #ifdef HAVE_SIGACTION - action.sa_sigaction = faulthandler_fatal_error; + action.sa_handler = faulthandler_fatal_error; sigemptyset(&action.sa_mask); /* Do not prevent the signal from being received from within its own signal handler */ @@ -451,8 +450,8 @@ } static PyObject* -faulthandler_dump_traceback_later(PyObject *self, - PyObject *args, PyObject *kwargs) +faulthandler_dump_tracebacks_later(PyObject *self, + PyObject *args, PyObject *kwargs) { static char *kwlist[] = {"timeout", "repeat", "file", "exit", NULL}; double timeout; @@ -461,6 +460,7 @@ PyObject *file = NULL; int fd; int exit = 0; + PyThreadState *tstate; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "d|iOi:dump_tracebacks_later", kwlist, @@ -477,6 +477,13 @@ return NULL; } + tstate = PyThreadState_Get(); + if (tstate == NULL) { + PyErr_SetString(PyExc_RuntimeError, + "unable to get the current thread state"); + return NULL; + } + file = faulthandler_get_fileno(file, &fd); if (file == NULL) return NULL; @@ -490,7 +497,7 @@ thread.fd = fd; thread.timeout_ms = timeout_ms; thread.repeat = repeat; - thread.interp = PyThreadState_Get()->interp; + thread.interp = tstate->interp; thread.exit = exit; /* Arm these locks to serve as events when released */ @@ -537,10 +544,14 @@ if (!user->enabled) return; +#ifdef WITH_THREAD /* PyThreadState_Get() doesn't give the state of the current thread if the thread doesn't hold the GIL. Read the thread local storage (TLS) instead: call PyGILState_GetThisThreadState(). */ tstate = PyGILState_GetThisThreadState(); +#else + tstate = PyThreadState_Get(); +#endif if (user->all_threads) _Py_DumpTracebackThreads(user->fd, user->interp, tstate); @@ -826,7 +837,7 @@ faulthandler_traverse(PyObject *module, visitproc visit, void *arg) { #ifdef FAULTHANDLER_USER - unsigned int index; + unsigned int signum; #endif #ifdef FAULTHANDLER_LATER @@ -834,8 +845,8 @@ #endif #ifdef FAULTHANDLER_USER if (user_signals != NULL) { - for (index=0; index < NSIG; index++) - Py_VISIT(user_signals[index].file); + for (signum=0; signum < NSIG; signum++) + Py_VISIT(user_signals[signum].file); } #endif Py_VISIT(fatal_error.file); @@ -861,10 +872,11 @@ "if all_threads is True, into file")}, #ifdef FAULTHANDLER_LATER {"dump_tracebacks_later", - (PyCFunction)faulthandler_dump_traceback_later, METH_VARARGS|METH_KEYWORDS, - PyDoc_STR("dump_tracebacks_later(timeout, repeat=False, file=sys.stderr):\n" + (PyCFunction)faulthandler_dump_tracebacks_later, METH_VARARGS|METH_KEYWORDS, + PyDoc_STR("dump_tracebacks_later(timeout, repeat=False, file=sys.stderrn, exit=False):\n" "dump the traceback of all threads in timeout seconds,\n" - "or each timeout seconds if repeat is True.")}, + "or each timeout seconds if repeat is True. If exit is True, " + "call _exit(1) which is not safe.")}, {"cancel_dump_tracebacks_later", (PyCFunction)faulthandler_cancel_dump_tracebacks_later_py, METH_NOARGS, PyDoc_STR("cancel_dump_tracebacks_later():\ncancel the previous call " diff --git a/setup.py b/setup.py --- a/setup.py +++ b/setup.py @@ -373,6 +373,8 @@ def add_multiarch_paths(self): # Debian/Ubuntu multiarch support. # https://wiki.ubuntu.com/MultiarchSpec + if not find_executable('dpkg-architecture'): + return tmpfile = os.path.join(self.build_temp, 'multiarch') if not os.path.exists(self.build_temp): os.makedirs(self.build_temp) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 8 02:35:12 2011 From: python-checkins at python.org (vinay.sajip) Date: Fri, 08 Apr 2011 02:35:12 +0200 Subject: [Python-checkins] cpython (3.2): Updated Formatter documentation. Message-ID: http://hg.python.org/cpython/rev/c760390165dc changeset: 69194:c760390165dc branch: 3.2 parent: 69189:225400cb6e84 user: Vinay Sajip date: Fri Apr 08 01:30:51 2011 +0100 summary: Updated Formatter documentation. files: Doc/library/logging.rst | 11 +++++++++-- 1 files changed, 9 insertions(+), 2 deletions(-) diff --git a/Doc/library/logging.rst b/Doc/library/logging.rst --- a/Doc/library/logging.rst +++ b/Doc/library/logging.rst @@ -405,7 +405,7 @@ :ref:`logrecord-attributes`. -.. class:: Formatter(fmt=None, datefmt=None) +.. class:: Formatter(fmt=None, datefmt=None, style='%') Returns a new instance of the :class:`Formatter` class. The instance is initialized with a format string for the message as a whole, as well as a @@ -413,6 +413,14 @@ specified, ``'%(message)s'`` is used. If no *datefmt* is specified, the ISO8601 date format is used. + The *style* parameter can be one of '%', '{' or '$' and determines how + the format string will be merged with its data: using one of %-formatting, + :meth:`str.format` or :class:`string.Template`. + + .. versionchanged:: 3.2 + The *style* parameter was added. + + .. method:: format(record) The record's attribute dictionary is used as the operand to a string @@ -691,7 +699,6 @@ information into logging calls. For a usage example , see the section on :ref:`adding contextual information to your logging output `. - .. class:: LoggerAdapter(logger, extra) Returns an instance of :class:`LoggerAdapter` initialized with an -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 8 02:35:16 2011 From: python-checkins at python.org (vinay.sajip) Date: Fri, 08 Apr 2011 02:35:16 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merged doc fix in 3.2. Message-ID: http://hg.python.org/cpython/rev/93f6ffe53b99 changeset: 69195:93f6ffe53b99 parent: 69193:9ddba521c3aa parent: 69194:c760390165dc user: Vinay Sajip date: Fri Apr 08 01:32:27 2011 +0100 summary: Merged doc fix in 3.2. files: Doc/library/logging.rst | 11 +++++++++-- 1 files changed, 9 insertions(+), 2 deletions(-) diff --git a/Doc/library/logging.rst b/Doc/library/logging.rst --- a/Doc/library/logging.rst +++ b/Doc/library/logging.rst @@ -405,7 +405,7 @@ :ref:`logrecord-attributes`. -.. class:: Formatter(fmt=None, datefmt=None) +.. class:: Formatter(fmt=None, datefmt=None, style='%') Returns a new instance of the :class:`Formatter` class. The instance is initialized with a format string for the message as a whole, as well as a @@ -413,6 +413,14 @@ specified, ``'%(message)s'`` is used. If no *datefmt* is specified, the ISO8601 date format is used. + The *style* parameter can be one of '%', '{' or '$' and determines how + the format string will be merged with its data: using one of %-formatting, + :meth:`str.format` or :class:`string.Template`. + + .. versionchanged:: 3.2 + The *style* parameter was added. + + .. method:: format(record) The record's attribute dictionary is used as the operand to a string @@ -691,7 +699,6 @@ information into logging calls. For a usage example , see the section on :ref:`adding contextual information to your logging output `. - .. class:: LoggerAdapter(logger, extra) Returns an instance of :class:`LoggerAdapter` initialized with an -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 8 02:35:17 2011 From: python-checkins at python.org (vinay.sajip) Date: Fri, 08 Apr 2011 02:35:17 +0200 Subject: [Python-checkins] cpython (3.2): Normalised whitespace. Message-ID: http://hg.python.org/cpython/rev/4995dfe308e7 changeset: 69196:4995dfe308e7 branch: 3.2 parent: 69194:c760390165dc user: Vinay Sajip date: Fri Apr 08 01:34:20 2011 +0100 summary: Normalised whitespace. files: Doc/library/logging.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/logging.rst b/Doc/library/logging.rst --- a/Doc/library/logging.rst +++ b/Doc/library/logging.rst @@ -415,7 +415,7 @@ The *style* parameter can be one of '%', '{' or '$' and determines how the format string will be merged with its data: using one of %-formatting, - :meth:`str.format` or :class:`string.Template`. + :meth:`str.format` or :class:`string.Template`. .. versionchanged:: 3.2 The *style* parameter was added. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 8 02:35:19 2011 From: python-checkins at python.org (vinay.sajip) Date: Fri, 08 Apr 2011 02:35:19 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merged whitespace fix. Message-ID: http://hg.python.org/cpython/rev/664e065ed3cd changeset: 69197:664e065ed3cd parent: 69195:93f6ffe53b99 parent: 69196:4995dfe308e7 user: Vinay Sajip date: Fri Apr 08 01:35:04 2011 +0100 summary: Merged whitespace fix. files: Doc/library/logging.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/logging.rst b/Doc/library/logging.rst --- a/Doc/library/logging.rst +++ b/Doc/library/logging.rst @@ -415,7 +415,7 @@ The *style* parameter can be one of '%', '{' or '$' and determines how the format string will be merged with its data: using one of %-formatting, - :meth:`str.format` or :class:`string.Template`. + :meth:`str.format` or :class:`string.Template`. .. versionchanged:: 3.2 The *style* parameter was added. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 8 02:42:42 2011 From: python-checkins at python.org (r.david.murray) Date: Fri, 08 Apr 2011 02:42:42 +0200 Subject: [Python-checkins] cpython (3.1): Improve test coverage of _split_ascii method. Message-ID: http://hg.python.org/cpython/rev/0e76c8ddd989 changeset: 69198:0e76c8ddd989 branch: 3.1 parent: 69185:c8738114b962 user: R David Murray date: Thu Apr 07 20:37:17 2011 -0400 summary: Improve test coverage of _split_ascii method. files: Lib/email/test/test_email.py | 43 ++++++++++++++++++++++++ 1 files changed, 43 insertions(+), 0 deletions(-) diff --git a/Lib/email/test/test_email.py b/Lib/email/test/test_email.py --- a/Lib/email/test/test_email.py +++ b/Lib/email/test/test_email.py @@ -750,6 +750,49 @@ Test""") + def test_last_split_chunk_does_not_fit(self): + eq = self.ndiffAssertEqual + h = Header('Subject: the first part of this is short, but_the_second' + '_part_does_not_fit_within_maxlinelen_and_thus_should_be_on_a_line' + '_all_by_itself') + eq(h.encode(), """\ +Subject: the first part of this is short, + but_the_second_part_does_not_fit_within_maxlinelen_and_thus_should_be_on_a_line_all_by_itself""") + + def test_splittable_leading_char_followed_by_overlong_unsplitable(self): + eq = self.ndiffAssertEqual + h = Header(', but_the_second' + '_part_does_not_fit_within_maxlinelen_and_thus_should_be_on_a_line' + '_all_by_itself') + eq(h.encode(), """\ +, + but_the_second_part_does_not_fit_within_maxlinelen_and_thus_should_be_on_a_line_all_by_itself""") + + def test_multiple_splittable_leading_char_followed_by_overlong_unsplitable(self): + eq = self.ndiffAssertEqual + h = Header(', , but_the_second' + '_part_does_not_fit_within_maxlinelen_and_thus_should_be_on_a_line' + '_all_by_itself') + eq(h.encode(), """\ +, , + but_the_second_part_does_not_fit_within_maxlinelen_and_thus_should_be_on_a_line_all_by_itself""") + + def test_trailing_splitable_on_overlong_unsplitable(self): + eq = self.ndiffAssertEqual + h = Header('this_part_does_not_fit_within_maxlinelen_and_thus_should_' + 'be_on_a_line_all_by_itself;') + eq(h.encode(), "this_part_does_not_fit_within_maxlinelen_and_thus_should_" + "be_on_a_line_all_by_itself;") + + def test_trailing_splitable_on_overlong_unsplitable_with_leading_splitable(self): + eq = self.ndiffAssertEqual + h = Header('; ' + 'this_part_does_not_fit_within_maxlinelen_and_thus_should_' + 'be_on_a_line_all_by_itself;') + eq(h.encode(), """\ +; + this_part_does_not_fit_within_maxlinelen_and_thus_should_be_on_a_line_all_by_itself;""") + def test_no_split_long_header(self): eq = self.ndiffAssertEqual hstr = 'References: ' + 'x' * 80 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 8 02:42:43 2011 From: python-checkins at python.org (r.david.murray) Date: Fri, 08 Apr 2011 02:42:43 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): Merge: Improve test coverage of _split_ascii method. Message-ID: http://hg.python.org/cpython/rev/bc1117ace406 changeset: 69199:bc1117ace406 branch: 3.2 parent: 69196:4995dfe308e7 parent: 69198:0e76c8ddd989 user: R David Murray date: Thu Apr 07 20:40:01 2011 -0400 summary: Merge: Improve test coverage of _split_ascii method. files: Lib/email/test/test_email.py | 43 ++++++++++++++++++++++++ 1 files changed, 43 insertions(+), 0 deletions(-) diff --git a/Lib/email/test/test_email.py b/Lib/email/test/test_email.py --- a/Lib/email/test/test_email.py +++ b/Lib/email/test/test_email.py @@ -784,6 +784,49 @@ Test""") + def test_last_split_chunk_does_not_fit(self): + eq = self.ndiffAssertEqual + h = Header('Subject: the first part of this is short, but_the_second' + '_part_does_not_fit_within_maxlinelen_and_thus_should_be_on_a_line' + '_all_by_itself') + eq(h.encode(), """\ +Subject: the first part of this is short, + but_the_second_part_does_not_fit_within_maxlinelen_and_thus_should_be_on_a_line_all_by_itself""") + + def test_splittable_leading_char_followed_by_overlong_unsplitable(self): + eq = self.ndiffAssertEqual + h = Header(', but_the_second' + '_part_does_not_fit_within_maxlinelen_and_thus_should_be_on_a_line' + '_all_by_itself') + eq(h.encode(), """\ +, + but_the_second_part_does_not_fit_within_maxlinelen_and_thus_should_be_on_a_line_all_by_itself""") + + def test_multiple_splittable_leading_char_followed_by_overlong_unsplitable(self): + eq = self.ndiffAssertEqual + h = Header(', , but_the_second' + '_part_does_not_fit_within_maxlinelen_and_thus_should_be_on_a_line' + '_all_by_itself') + eq(h.encode(), """\ +, , + but_the_second_part_does_not_fit_within_maxlinelen_and_thus_should_be_on_a_line_all_by_itself""") + + def test_trailing_splitable_on_overlong_unsplitable(self): + eq = self.ndiffAssertEqual + h = Header('this_part_does_not_fit_within_maxlinelen_and_thus_should_' + 'be_on_a_line_all_by_itself;') + eq(h.encode(), "this_part_does_not_fit_within_maxlinelen_and_thus_should_" + "be_on_a_line_all_by_itself;") + + def test_trailing_splitable_on_overlong_unsplitable_with_leading_splitable(self): + eq = self.ndiffAssertEqual + h = Header('; ' + 'this_part_does_not_fit_within_maxlinelen_and_thus_should_' + 'be_on_a_line_all_by_itself;') + eq(h.encode(), """\ +; + this_part_does_not_fit_within_maxlinelen_and_thus_should_be_on_a_line_all_by_itself;""") + def test_no_split_long_header(self): eq = self.ndiffAssertEqual hstr = 'References: ' + 'x' * 80 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 8 02:42:45 2011 From: python-checkins at python.org (r.david.murray) Date: Fri, 08 Apr 2011 02:42:45 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge: Improve test coverage of _split_ascii method. Message-ID: http://hg.python.org/cpython/rev/d48b886dd750 changeset: 69200:d48b886dd750 parent: 69197:664e065ed3cd parent: 69199:bc1117ace406 user: R David Murray date: Thu Apr 07 20:42:28 2011 -0400 summary: Merge: Improve test coverage of _split_ascii method. files: Lib/test/test_email/test_email.py | 43 +++++++++++++++++++ 1 files changed, 43 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_email/test_email.py b/Lib/test/test_email/test_email.py --- a/Lib/test/test_email/test_email.py +++ b/Lib/test/test_email/test_email.py @@ -758,6 +758,49 @@ Test""") + def test_last_split_chunk_does_not_fit(self): + eq = self.ndiffAssertEqual + h = Header('Subject: the first part of this is short, but_the_second' + '_part_does_not_fit_within_maxlinelen_and_thus_should_be_on_a_line' + '_all_by_itself') + eq(h.encode(), """\ +Subject: the first part of this is short, + but_the_second_part_does_not_fit_within_maxlinelen_and_thus_should_be_on_a_line_all_by_itself""") + + def test_splittable_leading_char_followed_by_overlong_unsplitable(self): + eq = self.ndiffAssertEqual + h = Header(', but_the_second' + '_part_does_not_fit_within_maxlinelen_and_thus_should_be_on_a_line' + '_all_by_itself') + eq(h.encode(), """\ +, + but_the_second_part_does_not_fit_within_maxlinelen_and_thus_should_be_on_a_line_all_by_itself""") + + def test_multiple_splittable_leading_char_followed_by_overlong_unsplitable(self): + eq = self.ndiffAssertEqual + h = Header(', , but_the_second' + '_part_does_not_fit_within_maxlinelen_and_thus_should_be_on_a_line' + '_all_by_itself') + eq(h.encode(), """\ +, , + but_the_second_part_does_not_fit_within_maxlinelen_and_thus_should_be_on_a_line_all_by_itself""") + + def test_trailing_splitable_on_overlong_unsplitable(self): + eq = self.ndiffAssertEqual + h = Header('this_part_does_not_fit_within_maxlinelen_and_thus_should_' + 'be_on_a_line_all_by_itself;') + eq(h.encode(), "this_part_does_not_fit_within_maxlinelen_and_thus_should_" + "be_on_a_line_all_by_itself;") + + def test_trailing_splitable_on_overlong_unsplitable_with_leading_splitable(self): + eq = self.ndiffAssertEqual + h = Header('; ' + 'this_part_does_not_fit_within_maxlinelen_and_thus_should_' + 'be_on_a_line_all_by_itself;') + eq(h.encode(), """\ +; + this_part_does_not_fit_within_maxlinelen_and_thus_should_be_on_a_line_all_by_itself;""") + def test_no_split_long_header(self): eq = self.ndiffAssertEqual hstr = 'References: ' + 'x' * 80 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 8 03:01:27 2011 From: python-checkins at python.org (r.david.murray) Date: Fri, 08 Apr 2011 03:01:27 +0200 Subject: [Python-checkins] cpython (3.1): #11492: fix header truncation on folding when there are runs of split chars. Message-ID: http://hg.python.org/cpython/rev/10725fc76e11 changeset: 69201:10725fc76e11 branch: 3.1 parent: 69198:0e76c8ddd989 user: R David Murray date: Thu Apr 07 20:54:03 2011 -0400 summary: #11492: fix header truncation on folding when there are runs of split chars. Not a complete fix for this issue. files: Lib/email/header.py | 7 ++++--- Lib/email/test/test_email.py | 10 ++++++++++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/Lib/email/header.py b/Lib/email/header.py --- a/Lib/email/header.py +++ b/Lib/email/header.py @@ -464,12 +464,13 @@ self._current_line.reset(str(holding)) return elif not nextpart: - # There must be some trailing split characters because we + # There must be some trailing or duplicated split characters + # because we # found a split character but no next part. In this case we # must treat the thing to fit as the part + splitpart because # if splitpart is whitespace it's not allowed to be the only # thing on the line, and if it's not whitespace we must split - # after the syntactic break. In either case, we're done. + # after the syntactic break. holding_prelen = len(holding) holding.push(part + splitpart) if len(holding) + len(self._current_line) <= self._maxlen: @@ -484,7 +485,7 @@ self._lines.append(str(self._current_line)) holding.reset(save_part) self._current_line.reset(str(holding)) - return + holding.reset() elif not part: # We're leading with a split character. See if the splitpart # and nextpart fits on the current line. diff --git a/Lib/email/test/test_email.py b/Lib/email/test/test_email.py --- a/Lib/email/test/test_email.py +++ b/Lib/email/test/test_email.py @@ -793,6 +793,16 @@ ; this_part_does_not_fit_within_maxlinelen_and_thus_should_be_on_a_line_all_by_itself;""") + def test_long_header_with_multiple_sequential_split_chars(self): + # Issue 11492 + + eq = self.ndiffAssertEqual + h = Header('This is a long line that has two whitespaces in a row. ' + 'This used to cause truncation of the header when folded') + eq(h.encode(), """\ +This is a long line that has two whitespaces in a row. This used to cause + truncation of the header when folded""") + def test_no_split_long_header(self): eq = self.ndiffAssertEqual hstr = 'References: ' + 'x' * 80 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 8 03:01:28 2011 From: python-checkins at python.org (r.david.murray) Date: Fri, 08 Apr 2011 03:01:28 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): Merge #11492: fix header truncation on folding when there are runs of split Message-ID: http://hg.python.org/cpython/rev/74ec64dc3538 changeset: 69202:74ec64dc3538 branch: 3.2 parent: 69199:bc1117ace406 parent: 69201:10725fc76e11 user: R David Murray date: Thu Apr 07 20:56:31 2011 -0400 summary: Merge #11492: fix header truncation on folding when there are runs of split chars. Not a complete fix for this issue. files: Lib/email/header.py | 7 ++++--- Lib/email/test/test_email.py | 10 ++++++++++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/Lib/email/header.py b/Lib/email/header.py --- a/Lib/email/header.py +++ b/Lib/email/header.py @@ -483,12 +483,13 @@ self._current_line.reset(str(holding)) return elif not nextpart: - # There must be some trailing split characters because we + # There must be some trailing or duplicated split characters + # because we # found a split character but no next part. In this case we # must treat the thing to fit as the part + splitpart because # if splitpart is whitespace it's not allowed to be the only # thing on the line, and if it's not whitespace we must split - # after the syntactic break. In either case, we're done. + # after the syntactic break. holding_prelen = len(holding) holding.push(part + splitpart) if len(holding) + len(self._current_line) <= self._maxlen: @@ -503,7 +504,7 @@ self._lines.append(str(self._current_line)) holding.reset(save_part) self._current_line.reset(str(holding)) - return + holding.reset() elif not part: # We're leading with a split character. See if the splitpart # and nextpart fits on the current line. diff --git a/Lib/email/test/test_email.py b/Lib/email/test/test_email.py --- a/Lib/email/test/test_email.py +++ b/Lib/email/test/test_email.py @@ -827,6 +827,16 @@ ; this_part_does_not_fit_within_maxlinelen_and_thus_should_be_on_a_line_all_by_itself;""") + def test_long_header_with_multiple_sequential_split_chars(self): + # Issue 11492 + + eq = self.ndiffAssertEqual + h = Header('This is a long line that has two whitespaces in a row. ' + 'This used to cause truncation of the header when folded') + eq(h.encode(), """\ +This is a long line that has two whitespaces in a row. This used to cause + truncation of the header when folded""") + def test_no_split_long_header(self): eq = self.ndiffAssertEqual hstr = 'References: ' + 'x' * 80 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 8 03:01:31 2011 From: python-checkins at python.org (r.david.murray) Date: Fri, 08 Apr 2011 03:01:31 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge #11492: fix header truncation on folding when there are runs of split Message-ID: http://hg.python.org/cpython/rev/5ec2695c9c15 changeset: 69203:5ec2695c9c15 parent: 69200:d48b886dd750 parent: 69202:74ec64dc3538 user: R David Murray date: Thu Apr 07 21:00:33 2011 -0400 summary: Merge #11492: fix header truncation on folding when there are runs of split chars. Not a complete fix for this issue. files: Lib/email/header.py | 7 ++++--- Lib/test/test_email/test_email.py | 10 ++++++++++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/Lib/email/header.py b/Lib/email/header.py --- a/Lib/email/header.py +++ b/Lib/email/header.py @@ -483,12 +483,13 @@ self._current_line.reset(str(holding)) return elif not nextpart: - # There must be some trailing split characters because we + # There must be some trailing or duplicated split characters + # because we # found a split character but no next part. In this case we # must treat the thing to fit as the part + splitpart because # if splitpart is whitespace it's not allowed to be the only # thing on the line, and if it's not whitespace we must split - # after the syntactic break. In either case, we're done. + # after the syntactic break. holding_prelen = len(holding) holding.push(part + splitpart) if len(holding) + len(self._current_line) <= self._maxlen: @@ -503,7 +504,7 @@ self._lines.append(str(self._current_line)) holding.reset(save_part) self._current_line.reset(str(holding)) - return + holding.reset() elif not part: # We're leading with a split character. See if the splitpart # and nextpart fits on the current line. diff --git a/Lib/test/test_email/test_email.py b/Lib/test/test_email/test_email.py --- a/Lib/test/test_email/test_email.py +++ b/Lib/test/test_email/test_email.py @@ -801,6 +801,16 @@ ; this_part_does_not_fit_within_maxlinelen_and_thus_should_be_on_a_line_all_by_itself;""") + def test_long_header_with_multiple_sequential_split_chars(self): + # Issue 11492 + + eq = self.ndiffAssertEqual + h = Header('This is a long line that has two whitespaces in a row. ' + 'This used to cause truncation of the header when folded') + eq(h.encode(), """\ +This is a long line that has two whitespaces in a row. This used to cause + truncation of the header when folded""") + def test_no_split_long_header(self): eq = self.ndiffAssertEqual hstr = 'References: ' + 'x' * 80 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 8 03:42:09 2011 From: python-checkins at python.org (ezio.melotti) Date: Fri, 8 Apr 2011 03:42:09 +0200 (CEST) Subject: [Python-checkins] r88811 - tracker/instances/python-dev/html/issue.item.js Message-ID: <3Q5NnY35NLzQ8f@mail.python.org> Author: ezio.melotti Date: Fri Apr 8 03:42:09 2011 New Revision: 88811 Log: #390: Fix regex to allow names with spaces. Modified: tracker/instances/python-dev/html/issue.item.js Modified: tracker/instances/python-dev/html/issue.item.js ============================================================================== --- tracker/instances/python-dev/html/issue.item.js (original) +++ tracker/instances/python-dev/html/issue.item.js Fri Apr 8 03:42:09 2011 @@ -23,7 +23,7 @@ function add_to_nosy(user) { var add_me_button = document.getElementById('add_me_to_nosy'); var nosy = document.getElementsByName('nosy')[0]; - var nosy_text = nosy.value.replace(/\s+/g, ''); + var nosy_text = nosy.value.replace(/,\s+/g, ','); if (nosy_text == "") { // nosy_list is empty, add the user nosy.value = user; From python-checkins at python.org Fri Apr 8 04:41:44 2011 From: python-checkins at python.org (ezio.melotti) Date: Fri, 8 Apr 2011 04:41:44 +0200 (CEST) Subject: [Python-checkins] r88812 - tracker/instances/python-dev/html/style.css Message-ID: <3Q5Q6J62zJzRVW@mail.python.org> Author: ezio.melotti Date: Fri Apr 8 04:41:44 2011 New Revision: 88812 Log: #385: remove unnecessary whitespace. Modified: tracker/instances/python-dev/html/style.css Modified: tracker/instances/python-dev/html/style.css ============================================================================== --- tracker/instances/python-dev/html/style.css (original) +++ tracker/instances/python-dev/html/style.css Fri Apr 8 04:41:44 2011 @@ -21,7 +21,7 @@ margin: 0px; } - at media print + at media print { .index-controls { display: none;} #searchbox { display: none;} @@ -34,17 +34,29 @@ } -div#searchbox +div#searchbox { float: right; padding-top: 1em; } -div#searchbox input#search-text +div#searchbox input#search-text { width: 10em; } +#body-main { + margin-left: 14em; +} + +#menu +{ + width: 13em; +} +#menu ul.level-one li a +{ + margin-left: 0; +} #menu ul.level-two li { background-image: none; @@ -53,11 +65,11 @@ border: 0; border-top: 1px solid #DDD; padding: 0.1em; - margin: 0 3em 0px 1.5em; + margin: 0; color: #3C4B7B; background: none; width: 11em !important; - width /**/: 3.2em; + width /**/: 3.2em; font-family: Arial, Verdana, Geneva, "Bitstream Vera Sans", Helvetica, sans-serif; text-transform: none; } @@ -72,7 +84,7 @@ color: #5E72A5; background-image: none; width: 10em !important; - width /**/: 11.4em; + width /**/: 11.4em; font-family: Arial, Verdana, Geneva, "Bitstream Vera Sans", Helvetica, sans-serif; font-size: 95%; } @@ -100,25 +112,25 @@ } -td.date, th.date { +td.date, th.date { white-space: nowrap; } -p.ok-message +p.ok-message { background-color: #22bb22; padding: 5px; color: white; font-weight: bold; } -p.error-message +p.error-message { background-color: #bb2222; padding: 5px; color: white; font-weight: bold; } -p.error-message a[href] +p.error-message a[href] { color: white; text-decoration: underline; @@ -143,7 +155,7 @@ padding: 2px; border-spacing: 5px; border-collapse: collapse; -/* background-color: #e0e0e0; */ +/* background-color: #e0e0e0; */ margin: 5px; } @@ -203,7 +215,7 @@ table.list th a[href]:hover { color: #404070 } table.list th a[href]:link { color: #404070 } table.list th a[href] { color: #404070 } -table.list th.group +table.list th.group { background-color: #e0e0e0; text-align: center; @@ -364,7 +376,7 @@ /* style for class help display */ -table.classhelp { /* the table-layout: fixed; */ +table.classhelp { /* the table-layout: fixed; */ table-layout: fixed; /* compromises quality for speed */ overflow: hidden; font-size: .9em; From python-checkins at python.org Fri Apr 8 04:49:10 2011 From: python-checkins at python.org (ezio.melotti) Date: Fri, 8 Apr 2011 04:49:10 +0200 (CEST) Subject: [Python-checkins] r88813 - tracker/instances/python-dev/html/issue.item.html Message-ID: <3Q5QGt6D2Qz7Lpk@mail.python.org> Author: ezio.melotti Date: Fri Apr 8 04:49:10 2011 New Revision: 88813 Log: #390: Fix the check in the TAL too. Modified: tracker/instances/python-dev/html/issue.item.html Modified: tracker/instances/python-dev/html/issue.item.html ============================================================================== --- tracker/instances/python-dev/html/issue.item.html (original) +++ tracker/instances/python-dev/html/issue.item.html Fri Apr 8 04:49:10 2011 @@ -156,7 +156,7 @@ @@ -273,8 +273,8 @@ link#link# From solipsis at pitrou.net Fri Apr 8 04:56:38 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Fri, 08 Apr 2011 04:56:38 +0200 Subject: [Python-checkins] Daily reference leaks (5ec2695c9c15): sum=0 Message-ID: results for 5ec2695c9c15 on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogq6nYTr', '-x'] From python-checkins at python.org Fri Apr 8 11:49:10 2011 From: python-checkins at python.org (antoine.pitrou) Date: Fri, 08 Apr 2011 11:49:10 +0200 Subject: [Python-checkins] devguide: pydotorg -> python-committers Message-ID: http://hg.python.org/devguide/rev/91956ceea765 changeset: 410:91956ceea765 user: Antoine Pitrou date: Fri Apr 08 11:49:07 2011 +0200 summary: pydotorg -> python-committers files: coredev.rst | 6 +++--- faq.rst | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/coredev.rst b/coredev.rst --- a/coredev.rst +++ b/coredev.rst @@ -60,9 +60,9 @@ You need to generate an SSH 2 RSA key to be able to commit code. You may have multiple keys if you wish (e.g., for work and home). Send your key as an -attachment in an email to python-committers (do not paste it in the email as -SSH keys have specific formatting requirements). Help in generating an SSH key -can be found in the :ref:`faq`. +attachment in an email to python-committers at python.org (do not paste it in +the email as SSH keys have specific formatting requirements). Help in +generating an SSH key can be found in the :ref:`faq`. Your SSH key will be set to a username in the form of "first_name.last_name". This should match your username on the issue tracker. diff --git a/faq.rst b/faq.rst --- a/faq.rst +++ b/faq.rst @@ -676,8 +676,8 @@ How do I generate an SSH 2 public key? ------------------------------------------------------------------------------- -All generated SSH keys should be sent to pydotorg for adding to the list of -keys. +All generated SSH keys should be sent to python-committers at python.org for +adding to the list of keys. UNIX ''''''''''''''''''' -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Fri Apr 8 12:43:03 2011 From: python-checkins at python.org (vinay.sajip) Date: Fri, 08 Apr 2011 12:43:03 +0200 Subject: [Python-checkins] cpython (2.7): Issue #11794: Reorganised logging documentation. Message-ID: http://hg.python.org/cpython/rev/6fb033af9310 changeset: 69204:6fb033af9310 branch: 2.7 parent: 69188:bd0f73a9538e user: Vinay Sajip date: Fri Apr 08 11:40:38 2011 +0100 summary: Issue #11794: Reorganised logging documentation. files: Doc/howto/index.rst | 2 + Doc/howto/logging-cookbook.rst | 684 +++ Doc/howto/logging.rst | 998 ++++ Doc/library/allos.rst | 2 + Doc/library/logging.config.rst | 673 +++ Doc/library/logging.handlers.rst | 740 +++ Doc/library/logging.rst | 3875 ++--------------- 7 files changed, 3656 insertions(+), 3318 deletions(-) diff --git a/Doc/howto/index.rst b/Doc/howto/index.rst --- a/Doc/howto/index.rst +++ b/Doc/howto/index.rst @@ -19,6 +19,8 @@ descriptor.rst doanddont.rst functional.rst + logging.rst + logging-cookbook.rst regex.rst sockets.rst sorting.rst diff --git a/Doc/howto/logging-cookbook.rst b/Doc/howto/logging-cookbook.rst new file mode 100644 --- /dev/null +++ b/Doc/howto/logging-cookbook.rst @@ -0,0 +1,684 @@ +.. _logging-cookbook: + +================ +Logging Cookbook +================ + +:Author: Vinay Sajip + +This page contains a number of recipes related to logging, which have been found +useful in the past. + +.. currentmodule:: logging + +Using logging in multiple modules +--------------------------------- + +Multiple calls to ``logging.getLogger('someLogger')`` return a reference to the +same logger object. This is true not only within the same module, but also +across modules as long as it is in the same Python interpreter process. It is +true for references to the same object; additionally, application code can +define and configure a parent logger in one module and create (but not +configure) a child logger in a separate module, and all logger calls to the +child will pass up to the parent. Here is a main module:: + + import logging + import auxiliary_module + + # create logger with 'spam_application' + logger = logging.getLogger('spam_application') + logger.setLevel(logging.DEBUG) + # create file handler which logs even debug messages + fh = logging.FileHandler('spam.log') + fh.setLevel(logging.DEBUG) + # create console handler with a higher log level + ch = logging.StreamHandler() + ch.setLevel(logging.ERROR) + # create formatter and add it to the handlers + formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') + fh.setFormatter(formatter) + ch.setFormatter(formatter) + # add the handlers to the logger + logger.addHandler(fh) + logger.addHandler(ch) + + logger.info('creating an instance of auxiliary_module.Auxiliary') + a = auxiliary_module.Auxiliary() + logger.info('created an instance of auxiliary_module.Auxiliary') + logger.info('calling auxiliary_module.Auxiliary.do_something') + a.do_something() + logger.info('finished auxiliary_module.Auxiliary.do_something') + logger.info('calling auxiliary_module.some_function()') + auxiliary_module.some_function() + logger.info('done with auxiliary_module.some_function()') + +Here is the auxiliary module:: + + import logging + + # create logger + module_logger = logging.getLogger('spam_application.auxiliary') + + class Auxiliary: + def __init__(self): + self.logger = logging.getLogger('spam_application.auxiliary.Auxiliary') + self.logger.info('creating an instance of Auxiliary') + def do_something(self): + self.logger.info('doing something') + a = 1 + 1 + self.logger.info('done doing something') + + def some_function(): + module_logger.info('received a call to "some_function"') + +The output looks like this:: + + 2005-03-23 23:47:11,663 - spam_application - INFO - + creating an instance of auxiliary_module.Auxiliary + 2005-03-23 23:47:11,665 - spam_application.auxiliary.Auxiliary - INFO - + creating an instance of Auxiliary + 2005-03-23 23:47:11,665 - spam_application - INFO - + created an instance of auxiliary_module.Auxiliary + 2005-03-23 23:47:11,668 - spam_application - INFO - + calling auxiliary_module.Auxiliary.do_something + 2005-03-23 23:47:11,668 - spam_application.auxiliary.Auxiliary - INFO - + doing something + 2005-03-23 23:47:11,669 - spam_application.auxiliary.Auxiliary - INFO - + done doing something + 2005-03-23 23:47:11,670 - spam_application - INFO - + finished auxiliary_module.Auxiliary.do_something + 2005-03-23 23:47:11,671 - spam_application - INFO - + calling auxiliary_module.some_function() + 2005-03-23 23:47:11,672 - spam_application.auxiliary - INFO - + received a call to 'some_function' + 2005-03-23 23:47:11,673 - spam_application - INFO - + done with auxiliary_module.some_function() + +Multiple handlers and formatters +-------------------------------- + +Loggers are plain Python objects. The :func:`addHandler` method has no minimum +or maximum quota for the number of handlers you may add. Sometimes it will be +beneficial for an application to log all messages of all severities to a text +file while simultaneously logging errors or above to the console. To set this +up, simply configure the appropriate handlers. The logging calls in the +application code will remain unchanged. Here is a slight modification to the +previous simple module-based configuration example:: + + import logging + + logger = logging.getLogger('simple_example') + logger.setLevel(logging.DEBUG) + # create file handler which logs even debug messages + fh = logging.FileHandler('spam.log') + fh.setLevel(logging.DEBUG) + # create console handler with a higher log level + ch = logging.StreamHandler() + ch.setLevel(logging.ERROR) + # create formatter and add it to the handlers + formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') + ch.setFormatter(formatter) + fh.setFormatter(formatter) + # add the handlers to logger + logger.addHandler(ch) + logger.addHandler(fh) + + # 'application' code + logger.debug('debug message') + logger.info('info message') + logger.warn('warn message') + logger.error('error message') + logger.critical('critical message') + +Notice that the 'application' code does not care about multiple handlers. All +that changed was the addition and configuration of a new handler named *fh*. + +The ability to create new handlers with higher- or lower-severity filters can be +very helpful when writing and testing an application. Instead of using many +``print`` statements for debugging, use ``logger.debug``: Unlike the print +statements, which you will have to delete or comment out later, the logger.debug +statements can remain intact in the source code and remain dormant until you +need them again. At that time, the only change that needs to happen is to +modify the severity level of the logger and/or handler to debug. + +.. _multiple-destinations: + +Logging to multiple destinations +-------------------------------- + +Let's say you want to log to console and file with different message formats and +in differing circumstances. Say you want to log messages with levels of DEBUG +and higher to file, and those messages at level INFO and higher to the console. +Let's also assume that the file should contain timestamps, but the console +messages should not. Here's how you can achieve this:: + + import logging + + # set up logging to file - see previous section for more details + logging.basicConfig(level=logging.DEBUG, + format='%(asctime)s %(name)-12s %(levelname)-8s %(message)s', + datefmt='%m-%d %H:%M', + filename='/temp/myapp.log', + filemode='w') + # define a Handler which writes INFO messages or higher to the sys.stderr + console = logging.StreamHandler() + console.setLevel(logging.INFO) + # set a format which is simpler for console use + formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s') + # tell the handler to use this format + console.setFormatter(formatter) + # add the handler to the root logger + logging.getLogger('').addHandler(console) + + # Now, we can log to the root logger, or any other logger. First the root... + logging.info('Jackdaws love my big sphinx of quartz.') + + # Now, define a couple of other loggers which might represent areas in your + # application: + + logger1 = logging.getLogger('myapp.area1') + logger2 = logging.getLogger('myapp.area2') + + logger1.debug('Quick zephyrs blow, vexing daft Jim.') + logger1.info('How quickly daft jumping zebras vex.') + logger2.warning('Jail zesty vixen who grabbed pay from quack.') + logger2.error('The five boxing wizards jump quickly.') + +When you run this, on the console you will see :: + + root : INFO Jackdaws love my big sphinx of quartz. + myapp.area1 : INFO How quickly daft jumping zebras vex. + myapp.area2 : WARNING Jail zesty vixen who grabbed pay from quack. + myapp.area2 : ERROR The five boxing wizards jump quickly. + +and in the file you will see something like :: + + 10-22 22:19 root INFO Jackdaws love my big sphinx of quartz. + 10-22 22:19 myapp.area1 DEBUG Quick zephyrs blow, vexing daft Jim. + 10-22 22:19 myapp.area1 INFO How quickly daft jumping zebras vex. + 10-22 22:19 myapp.area2 WARNING Jail zesty vixen who grabbed pay from quack. + 10-22 22:19 myapp.area2 ERROR The five boxing wizards jump quickly. + +As you can see, the DEBUG message only shows up in the file. The other messages +are sent to both destinations. + +This example uses console and file handlers, but you can use any number and +combination of handlers you choose. + + +Configuration server example +---------------------------- + +Here is an example of a module using the logging configuration server:: + + import logging + import logging.config + import time + import os + + # read initial config file + logging.config.fileConfig('logging.conf') + + # create and start listener on port 9999 + t = logging.config.listen(9999) + t.start() + + logger = logging.getLogger('simpleExample') + + try: + # loop through logging calls to see the difference + # new configurations make, until Ctrl+C is pressed + while True: + logger.debug('debug message') + logger.info('info message') + logger.warn('warn message') + logger.error('error message') + logger.critical('critical message') + time.sleep(5) + except KeyboardInterrupt: + # cleanup + logging.config.stopListening() + t.join() + +And here is a script that takes a filename and sends that file to the server, +properly preceded with the binary-encoded length, as the new logging +configuration:: + + #!/usr/bin/env python + import socket, sys, struct + + with open(sys.argv[1], 'rb') as f: + data_to_send = f.read() + + HOST = 'localhost' + PORT = 9999 + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + print('connecting...') + s.connect((HOST, PORT)) + print('sending config...') + s.send(struct.pack('>L', len(data_to_send))) + s.send(data_to_send) + s.close() + print('complete') + + +.. _network-logging: + +Sending and receiving logging events across a network +----------------------------------------------------- + +Let's say you want to send logging events across a network, and handle them at +the receiving end. A simple way of doing this is attaching a +:class:`SocketHandler` instance to the root logger at the sending end:: + + import logging, logging.handlers + + rootLogger = logging.getLogger('') + rootLogger.setLevel(logging.DEBUG) + socketHandler = logging.handlers.SocketHandler('localhost', + logging.handlers.DEFAULT_TCP_LOGGING_PORT) + # don't bother with a formatter, since a socket handler sends the event as + # an unformatted pickle + rootLogger.addHandler(socketHandler) + + # Now, we can log to the root logger, or any other logger. First the root... + logging.info('Jackdaws love my big sphinx of quartz.') + + # Now, define a couple of other loggers which might represent areas in your + # application: + + logger1 = logging.getLogger('myapp.area1') + logger2 = logging.getLogger('myapp.area2') + + logger1.debug('Quick zephyrs blow, vexing daft Jim.') + logger1.info('How quickly daft jumping zebras vex.') + logger2.warning('Jail zesty vixen who grabbed pay from quack.') + logger2.error('The five boxing wizards jump quickly.') + +At the receiving end, you can set up a receiver using the :mod:`socketserver` +module. Here is a basic working example:: + + import pickle + import logging + import logging.handlers + import socketserver + import struct + + + class LogRecordStreamHandler(socketserver.StreamRequestHandler): + """Handler for a streaming logging request. + + This basically logs the record using whatever logging policy is + configured locally. + """ + + def handle(self): + """ + Handle multiple requests - each expected to be a 4-byte length, + followed by the LogRecord in pickle format. Logs the record + according to whatever policy is configured locally. + """ + while True: + chunk = self.connection.recv(4) + if len(chunk) < 4: + break + slen = struct.unpack('>L', chunk)[0] + chunk = self.connection.recv(slen) + while len(chunk) < slen: + chunk = chunk + self.connection.recv(slen - len(chunk)) + obj = self.unPickle(chunk) + record = logging.makeLogRecord(obj) + self.handleLogRecord(record) + + def unPickle(self, data): + return pickle.loads(data) + + def handleLogRecord(self, record): + # if a name is specified, we use the named logger rather than the one + # implied by the record. + if self.server.logname is not None: + name = self.server.logname + else: + name = record.name + logger = logging.getLogger(name) + # N.B. EVERY record gets logged. This is because Logger.handle + # is normally called AFTER logger-level filtering. If you want + # to do filtering, do it at the client end to save wasting + # cycles and network bandwidth! + logger.handle(record) + + class LogRecordSocketReceiver(socketserver.ThreadingTCPServer): + """ + Simple TCP socket-based logging receiver suitable for testing. + """ + + allow_reuse_address = 1 + + def __init__(self, host='localhost', + port=logging.handlers.DEFAULT_TCP_LOGGING_PORT, + handler=LogRecordStreamHandler): + socketserver.ThreadingTCPServer.__init__(self, (host, port), handler) + self.abort = 0 + self.timeout = 1 + self.logname = None + + def serve_until_stopped(self): + import select + abort = 0 + while not abort: + rd, wr, ex = select.select([self.socket.fileno()], + [], [], + self.timeout) + if rd: + self.handle_request() + abort = self.abort + + def main(): + logging.basicConfig( + format='%(relativeCreated)5d %(name)-15s %(levelname)-8s %(message)s') + tcpserver = LogRecordSocketReceiver() + print('About to start TCP server...') + tcpserver.serve_until_stopped() + + if __name__ == '__main__': + main() + +First run the server, and then the client. On the client side, nothing is +printed on the console; on the server side, you should see something like:: + + About to start TCP server... + 59 root INFO Jackdaws love my big sphinx of quartz. + 59 myapp.area1 DEBUG Quick zephyrs blow, vexing daft Jim. + 69 myapp.area1 INFO How quickly daft jumping zebras vex. + 69 myapp.area2 WARNING Jail zesty vixen who grabbed pay from quack. + 69 myapp.area2 ERROR The five boxing wizards jump quickly. + +Note that there are some security issues with pickle in some scenarios. If +these affect you, you can use an alternative serialization scheme by overriding +the :meth:`makePickle` method and implementing your alternative there, as +well as adapting the above script to use your alternative serialization. + + +.. _context-info: + +Adding contextual information to your logging output +---------------------------------------------------- + +Sometimes you want logging output to contain contextual information in +addition to the parameters passed to the logging call. For example, in a +networked application, it may be desirable to log client-specific information +in the log (e.g. remote client's username, or IP address). Although you could +use the *extra* parameter to achieve this, it's not always convenient to pass +the information in this way. While it might be tempting to create +:class:`Logger` instances on a per-connection basis, this is not a good idea +because these instances are not garbage collected. While this is not a problem +in practice, when the number of :class:`Logger` instances is dependent on the +level of granularity you want to use in logging an application, it could +be hard to manage if the number of :class:`Logger` instances becomes +effectively unbounded. + + +Using LoggerAdapters to impart contextual information +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +An easy way in which you can pass contextual information to be output along +with logging event information is to use the :class:`LoggerAdapter` class. +This class is designed to look like a :class:`Logger`, so that you can call +:meth:`debug`, :meth:`info`, :meth:`warning`, :meth:`error`, +:meth:`exception`, :meth:`critical` and :meth:`log`. These methods have the +same signatures as their counterparts in :class:`Logger`, so you can use the +two types of instances interchangeably. + +When you create an instance of :class:`LoggerAdapter`, you pass it a +:class:`Logger` instance and a dict-like object which contains your contextual +information. When you call one of the logging methods on an instance of +:class:`LoggerAdapter`, it delegates the call to the underlying instance of +:class:`Logger` passed to its constructor, and arranges to pass the contextual +information in the delegated call. Here's a snippet from the code of +:class:`LoggerAdapter`:: + + def debug(self, msg, *args, **kwargs): + """ + Delegate a debug call to the underlying logger, after adding + contextual information from this adapter instance. + """ + msg, kwargs = self.process(msg, kwargs) + self.logger.debug(msg, *args, **kwargs) + +The :meth:`process` method of :class:`LoggerAdapter` is where the contextual +information is added to the logging output. It's passed the message and +keyword arguments of the logging call, and it passes back (potentially) +modified versions of these to use in the call to the underlying logger. The +default implementation of this method leaves the message alone, but inserts +an 'extra' key in the keyword argument whose value is the dict-like object +passed to the constructor. Of course, if you had passed an 'extra' keyword +argument in the call to the adapter, it will be silently overwritten. + +The advantage of using 'extra' is that the values in the dict-like object are +merged into the :class:`LogRecord` instance's __dict__, allowing you to use +customized strings with your :class:`Formatter` instances which know about +the keys of the dict-like object. If you need a different method, e.g. if you +want to prepend or append the contextual information to the message string, +you just need to subclass :class:`LoggerAdapter` and override :meth:`process` +to do what you need. Here's an example script which uses this class, which +also illustrates what dict-like behaviour is needed from an arbitrary +'dict-like' object for use in the constructor:: + + import logging + + class ConnInfo: + """ + An example class which shows how an arbitrary class can be used as + the 'extra' context information repository passed to a LoggerAdapter. + """ + + def __getitem__(self, name): + """ + To allow this instance to look like a dict. + """ + from random import choice + if name == 'ip': + result = choice(['127.0.0.1', '192.168.0.1']) + elif name == 'user': + result = choice(['jim', 'fred', 'sheila']) + else: + result = self.__dict__.get(name, '?') + return result + + def __iter__(self): + """ + To allow iteration over keys, which will be merged into + the LogRecord dict before formatting and output. + """ + keys = ['ip', 'user'] + keys.extend(self.__dict__.keys()) + return keys.__iter__() + + if __name__ == '__main__': + from random import choice + levels = (logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR, logging.CRITICAL) + a1 = logging.LoggerAdapter(logging.getLogger('a.b.c'), + { 'ip' : '123.231.231.123', 'user' : 'sheila' }) + logging.basicConfig(level=logging.DEBUG, + format='%(asctime)-15s %(name)-5s %(levelname)-8s IP: %(ip)-15s User: %(user)-8s %(message)s') + a1.debug('A debug message') + a1.info('An info message with %s', 'some parameters') + a2 = logging.LoggerAdapter(logging.getLogger('d.e.f'), ConnInfo()) + for x in range(10): + lvl = choice(levels) + lvlname = logging.getLevelName(lvl) + a2.log(lvl, 'A message at %s level with %d %s', lvlname, 2, 'parameters') + +When this script is run, the output should look something like this:: + + 2008-01-18 14:49:54,023 a.b.c DEBUG IP: 123.231.231.123 User: sheila A debug message + 2008-01-18 14:49:54,023 a.b.c INFO IP: 123.231.231.123 User: sheila An info message with some parameters + 2008-01-18 14:49:54,023 d.e.f CRITICAL IP: 192.168.0.1 User: jim A message at CRITICAL level with 2 parameters + 2008-01-18 14:49:54,033 d.e.f INFO IP: 192.168.0.1 User: jim A message at INFO level with 2 parameters + 2008-01-18 14:49:54,033 d.e.f WARNING IP: 192.168.0.1 User: sheila A message at WARNING level with 2 parameters + 2008-01-18 14:49:54,033 d.e.f ERROR IP: 127.0.0.1 User: fred A message at ERROR level with 2 parameters + 2008-01-18 14:49:54,033 d.e.f ERROR IP: 127.0.0.1 User: sheila A message at ERROR level with 2 parameters + 2008-01-18 14:49:54,033 d.e.f WARNING IP: 192.168.0.1 User: sheila A message at WARNING level with 2 parameters + 2008-01-18 14:49:54,033 d.e.f WARNING IP: 192.168.0.1 User: jim A message at WARNING level with 2 parameters + 2008-01-18 14:49:54,033 d.e.f INFO IP: 192.168.0.1 User: fred A message at INFO level with 2 parameters + 2008-01-18 14:49:54,033 d.e.f WARNING IP: 192.168.0.1 User: sheila A message at WARNING level with 2 parameters + 2008-01-18 14:49:54,033 d.e.f WARNING IP: 127.0.0.1 User: jim A message at WARNING level with 2 parameters + + +.. _filters-contextual: + +Using Filters to impart contextual information +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +You can also add contextual information to log output using a user-defined +:class:`Filter`. ``Filter`` instances are allowed to modify the ``LogRecords`` +passed to them, including adding additional attributes which can then be output +using a suitable format string, or if needed a custom :class:`Formatter`. + +For example in a web application, the request being processed (or at least, +the interesting parts of it) can be stored in a threadlocal +(:class:`threading.local`) variable, and then accessed from a ``Filter`` to +add, say, information from the request - say, the remote IP address and remote +user's username - to the ``LogRecord``, using the attribute names 'ip' and +'user' as in the ``LoggerAdapter`` example above. In that case, the same format +string can be used to get similar output to that shown above. Here's an example +script:: + + import logging + from random import choice + + class ContextFilter(logging.Filter): + """ + This is a filter which injects contextual information into the log. + + Rather than use actual contextual information, we just use random + data in this demo. + """ + + USERS = ['jim', 'fred', 'sheila'] + IPS = ['123.231.231.123', '127.0.0.1', '192.168.0.1'] + + def filter(self, record): + + record.ip = choice(ContextFilter.IPS) + record.user = choice(ContextFilter.USERS) + return True + + if __name__ == '__main__': + levels = (logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR, logging.CRITICAL) + logging.basicConfig(level=logging.DEBUG, + format='%(asctime)-15s %(name)-5s %(levelname)-8s IP: %(ip)-15s User: %(user)-8s %(message)s') + a1 = logging.getLogger('a.b.c') + a2 = logging.getLogger('d.e.f') + + f = ContextFilter() + a1.addFilter(f) + a2.addFilter(f) + a1.debug('A debug message') + a1.info('An info message with %s', 'some parameters') + for x in range(10): + lvl = choice(levels) + lvlname = logging.getLevelName(lvl) + a2.log(lvl, 'A message at %s level with %d %s', lvlname, 2, 'parameters') + +which, when run, produces something like:: + + 2010-09-06 22:38:15,292 a.b.c DEBUG IP: 123.231.231.123 User: fred A debug message + 2010-09-06 22:38:15,300 a.b.c INFO IP: 192.168.0.1 User: sheila An info message with some parameters + 2010-09-06 22:38:15,300 d.e.f CRITICAL IP: 127.0.0.1 User: sheila A message at CRITICAL level with 2 parameters + 2010-09-06 22:38:15,300 d.e.f ERROR IP: 127.0.0.1 User: jim A message at ERROR level with 2 parameters + 2010-09-06 22:38:15,300 d.e.f DEBUG IP: 127.0.0.1 User: sheila A message at DEBUG level with 2 parameters + 2010-09-06 22:38:15,300 d.e.f ERROR IP: 123.231.231.123 User: fred A message at ERROR level with 2 parameters + 2010-09-06 22:38:15,300 d.e.f CRITICAL IP: 192.168.0.1 User: jim A message at CRITICAL level with 2 parameters + 2010-09-06 22:38:15,300 d.e.f CRITICAL IP: 127.0.0.1 User: sheila A message at CRITICAL level with 2 parameters + 2010-09-06 22:38:15,300 d.e.f DEBUG IP: 192.168.0.1 User: jim A message at DEBUG level with 2 parameters + 2010-09-06 22:38:15,301 d.e.f ERROR IP: 127.0.0.1 User: sheila A message at ERROR level with 2 parameters + 2010-09-06 22:38:15,301 d.e.f DEBUG IP: 123.231.231.123 User: fred A message at DEBUG level with 2 parameters + 2010-09-06 22:38:15,301 d.e.f INFO IP: 123.231.231.123 User: fred A message at INFO level with 2 parameters + + +.. _multiple-processes: + +Logging to a single file from multiple processes +------------------------------------------------ + +Although logging is thread-safe, and logging to a single file from multiple +threads in a single process *is* supported, logging to a single file from +*multiple processes* is *not* supported, because there is no standard way to +serialize access to a single file across multiple processes in Python. If you +need to log to a single file from multiple processes, one way of doing this is +to have all the processes log to a :class:`SocketHandler`, and have a separate +process which implements a socket server which reads from the socket and logs +to file. (If you prefer, you can dedicate one thread in one of the existing +processes to perform this function.) The following section documents this +approach in more detail and includes a working socket receiver which can be +used as a starting point for you to adapt in your own applications. + +If you are using a recent version of Python which includes the +:mod:`multiprocessing` module, you could write your own handler which uses the +:class:`Lock` class from this module to serialize access to the file from +your processes. The existing :class:`FileHandler` and subclasses do not make +use of :mod:`multiprocessing` at present, though they may do so in the future. +Note that at present, the :mod:`multiprocessing` module does not provide +working lock functionality on all platforms (see +http://bugs.python.org/issue3770). + +.. currentmodule:: logging.handlers + + +Using file rotation +------------------- + +.. sectionauthor:: Doug Hellmann, Vinay Sajip (changes) +.. (see ) + +Sometimes you want to let a log file grow to a certain size, then open a new +file and log to that. You may want to keep a certain number of these files, and +when that many files have been created, rotate the files so that the number of +files and the size of the files both remain bounded. For this usage pattern, the +logging package provides a :class:`RotatingFileHandler`:: + + import glob + import logging + import logging.handlers + + LOG_FILENAME = 'logging_rotatingfile_example.out' + + # Set up a specific logger with our desired output level + my_logger = logging.getLogger('MyLogger') + my_logger.setLevel(logging.DEBUG) + + # Add the log message handler to the logger + handler = logging.handlers.RotatingFileHandler( + LOG_FILENAME, maxBytes=20, backupCount=5) + + my_logger.addHandler(handler) + + # Log some messages + for i in range(20): + my_logger.debug('i = %d' % i) + + # See what files are created + logfiles = glob.glob('%s*' % LOG_FILENAME) + + for filename in logfiles: + print(filename) + +The result should be 6 separate files, each with part of the log history for the +application:: + + logging_rotatingfile_example.out + logging_rotatingfile_example.out.1 + logging_rotatingfile_example.out.2 + logging_rotatingfile_example.out.3 + logging_rotatingfile_example.out.4 + logging_rotatingfile_example.out.5 + +The most current file is always :file:`logging_rotatingfile_example.out`, +and each time it reaches the size limit it is renamed with the suffix +``.1``. Each of the existing backup files is renamed to increment the suffix +(``.1`` becomes ``.2``, etc.) and the ``.6`` file is erased. + +Obviously this example sets the log length much much too small as an extreme +example. You would want to set *maxBytes* to an appropriate value. + diff --git a/Doc/howto/logging.rst b/Doc/howto/logging.rst new file mode 100644 --- /dev/null +++ b/Doc/howto/logging.rst @@ -0,0 +1,998 @@ +============= +Logging HOWTO +============= + +:Author: Vinay Sajip + +.. _logging-basic-tutorial: + +.. currentmodule:: logging + +Basic Logging Tutorial +---------------------- + +Logging is a means of tracking events that happen when some software runs. The +software's developer adds logging calls to their code to indicate that certain +events have occurred. An event is described by a descriptive message which can +optionally contain variable data (i.e. data that is potentially different for +each occurrence of the event). Events also have an importance which the +developer ascribes to the event; the importance can also be called the *level* +or *severity*. + +When to use logging +^^^^^^^^^^^^^^^^^^^ + +Logging provides a set of convenience functions for simple logging usage. These +are :func:`debug`, :func:`info`, :func:`warning`, :func:`error` and +:func:`critical`. To determine when to use logging, see the table below, which +states, for each of a set of common tasks, the best tool to use for it. + ++-------------------------------------+--------------------------------------+ +| Task you want to perform | The best tool for the task | ++=====================================+======================================+ +| Display console output for ordinary | :func:`print` | +| usage of a command line script or | | +| program | | ++-------------------------------------+--------------------------------------+ +| Report events that occur during | :func:`logging.info` (or | +| normal operation of a program (e.g. | :func:`logging.debug` for very | +| for status monitoring or fault | detailed output for diagnostic | +| investigation) | purposes) | ++-------------------------------------+--------------------------------------+ +| Issue a warning regarding a | :func:`warnings.warn` in library | +| particular runtime event | code if the issue is avoidable and | +| | the client application should be | +| | modified to eliminate the warning | +| | | +| | :func:`logging.warning` if there is | +| | nothing the client application can do| +| | about the situation, but the event | +| | should still be noted | ++-------------------------------------+--------------------------------------+ +| Report an error regarding a | Raise an exception | +| particular runtime event | | ++-------------------------------------+--------------------------------------+ +| Report suppression of an error | :func:`logging.error`, | +| without raising an exception (e.g. | :func:`logging.exception` or | +| error handler in a long-running | :func:`logging.critical` as | +| server process) | appropriate for the specific error | +| | and application domain | ++-------------------------------------+--------------------------------------+ + +The logging functions are named after the level or severity of the events +they are used to track. The standard levels and their applicability are +described below (in increasing order of severity): + ++--------------+---------------------------------------------+ +| Level | When it's used | ++==============+=============================================+ +| ``DEBUG`` | Detailed information, typically of interest | +| | only when diagnosing problems. | ++--------------+---------------------------------------------+ +| ``INFO`` | Confirmation that things are working as | +| | expected. | ++--------------+---------------------------------------------+ +| ``WARNING`` | An indication that something unexpected | +| | happened, or indicative of some problem in | +| | the near future (e.g. 'disk space low'). | +| | The software is still working as expected. | ++--------------+---------------------------------------------+ +| ``ERROR`` | Due to a more serious problem, the software | +| | has not been able to perform some function. | ++--------------+---------------------------------------------+ +| ``CRITICAL`` | A serious error, indicating that the program| +| | itself may be unable to continue running. | ++--------------+---------------------------------------------+ + +The default level is ``WARNING``, which means that only events of this level +and above will be tracked, unless the logging package is configured to do +otherwise. + +Events that are tracked can be handled in different ways. The simplest way of +handling tracked events is to print them to the console. Another common way +is to write them to a disk file. + + +.. _howto-minimal-example: + +A simple example +^^^^^^^^^^^^^^^^ + +A very simple example is:: + + import logging + logging.warning('Watch out!') # will print a message to the console + logging.info('I told you so') # will not print anything + +If you type these lines into a script and run it, you'll see:: + + WARNING:root:Watch out! + +printed out on the console. The ``INFO`` message doesn't appear because the +default level is ``WARNING``. The printed message includes the indication of +the level and the description of the event provided in the logging call, i.e. +'Watch out!'. Don't worry about the 'root' part for now: it will be explained +later. The actual output can be formatted quite flexibly if you need that; +formatting options will also be explained later. + + +Logging to a file +^^^^^^^^^^^^^^^^^ + +A very common situation is that of recording logging events in a file, so let's +look at that next:: + + import logging + logging.basicConfig(filename='example.log',level=logging.DEBUG) + logging.debug('This message should go to the log file') + logging.info('So should this') + logging.warning('And this, too') + +And now if we open the file and look at what we have, we should find the log +messages:: + + DEBUG:root:This message should go to the log file + INFO:root:So should this + WARNING:root:And this, too + +This example also shows how you can set the logging level which acts as the +threshold for tracking. In this case, because we set the threshold to +``DEBUG``, all of the messages were printed. + +If you want to set the logging level from a command-line option such as:: + + --log=INFO + +and you have the value of the parameter passed for ``--log`` in some variable +*loglevel*, you can use:: + + getattr(logging, loglevel.upper()) + +to get the value which you'll pass to :func:`basicConfig` via the *level* +argument. You may want to error check any user input value, perhaps as in the +following example:: + + # assuming loglevel is bound to the string value obtained from the + # command line argument. Convert to upper case to allow the user to + # specify --log=DEBUG or --log=debug + numeric_level = getattr(logging, loglevel.upper(), None) + if not isinstance(numeric_level, int): + raise ValueError('Invalid log level: %s' % loglevel) + logging.basicConfig(level=numeric_level, ...) + +The call to :func:`basicConfig` should come *before* any calls to :func:`debug`, +:func:`info` etc. As it's intended as a one-off simple configuration facility, +only the first call will actually do anything: subsequent calls are effectively +no-ops. + +If you run the above script several times, the messages from successive runs +are appended to the file *example.log*. If you want each run to start afresh, +not remembering the messages from earlier runs, you can specify the *filemode* +argument, by changing the call in the above example to:: + + logging.basicConfig(filename='example.log', filemode='w', level=logging.DEBUG) + +The output will be the same as before, but the log file is no longer appended +to, so the messages from earlier runs are lost. + + +Logging from multiple modules +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +If your program consists of multiple modules, here's an example of how you +could organize logging in it:: + + # myapp.py + import logging + import mylib + + def main(): + logging.basicConfig(filename='myapp.log', level=logging.INFO) + logging.info('Started') + mylib.do_something() + logging.info('Finished') + + if __name__ == '__main__': + main() + +:: + + # mylib.py + import logging + + def do_something(): + logging.info('Doing something') + +If you run *myapp.py*, you should see this in *myapp.log*:: + + INFO:root:Started + INFO:root:Doing something + INFO:root:Finished + +which is hopefully what you were expecting to see. You can generalize this to +multiple modules, using the pattern in *mylib.py*. Note that for this simple +usage pattern, you won't know, by looking in the log file, *where* in your +application your messages came from, apart from looking at the event +description. If you want to track the location of your messages, you'll need +to refer to the documentation beyond the tutorial level -- see +:ref:`logging-advanced-tutorial`. + + +Logging variable data +^^^^^^^^^^^^^^^^^^^^^ + +To log variable data, use a format string for the event description message and +append the variable data as arguments. For example:: + + import logging + logging.warning('%s before you %s', 'Look', 'leap!') + +will display:: + + WARNING:root:Look before you leap! + +As you can see, merging of variable data into the event description message +uses the old, %-style of string formatting. This is for backwards +compatibility: the logging package pre-dates newer formatting options such as +:meth:`str.format` and :class:`string.Template`. These newer formatting +options *are* supported, but exploring them is outside the scope of this +tutorial. + + +Changing the format of displayed messages +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +To change the format which is used to display messages, you need to +specify the format you want to use:: + + import logging + logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.DEBUG) + logging.debug('This message should appear on the console') + logging.info('So should this') + logging.warning('And this, too') + +which would print:: + + DEBUG:This message should appear on the console + INFO:So should this + WARNING:And this, too + +Notice that the 'root' which appeared in earlier examples has disappeared. For +a full set of things that can appear in format strings, you can refer to the +documentation for :ref:`logrecord-attributes`, but for simple usage, you just +need the *levelname* (severity), *message* (event description, including +variable data) and perhaps to display when the event occurred. This is +described in the next section. + + +Displaying the date/time in messages +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +To display the date and time of an event, you would place '%(asctime)s' in +your format string:: + + import logging + logging.basicConfig(format='%(asctime)s %(message)s') + logging.warning('is when this event was logged.') + +which should print something like this:: + + 2010-12-12 11:41:42,612 is when this event was logged. + +The default format for date/time display (shown above) is ISO8601. If you need +more control over the formatting of the date/time, provide a *datefmt* +argument to ``basicConfig``, as in this example:: + + import logging + logging.basicConfig(format='%(asctime)s %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p') + logging.warning('is when this event was logged.') + +which would display something like this:: + + 12/12/2010 11:46:36 AM is when this event was logged. + +The format of the *datefmt* argument is the same as supported by +:func:`time.strftime`. + + +Next Steps +^^^^^^^^^^ + +That concludes the basic tutorial. It should be enough to get you up and +running with logging. There's a lot more that the logging package offers, but +to get the best out of it, you'll need to invest a little more of your time in +reading the following sections. If you're ready for that, grab some of your +favourite beverage and carry on. + +If your logging needs are simple, then use the above examples to incorporate +logging into your own scripts, and if you run into problems or don't +understand something, please post a question on the comp.lang.python Usenet +group (available at http://groups.google.com/group/comp.lang.python) and you +should receive help before too long. + +Still here? You can carry on reading the next few sections, which provide a +slightly more advanced/in-depth tutorial than the basic one above. After that, +you can take a look at the :ref:`logging-cookbook`. + +.. _logging-advanced-tutorial: + + +Advanced Logging Tutorial +------------------------- + +The logging library takes a modular approach and offers several categories +of components: loggers, handlers, filters, and formatters. + +* Loggers expose the interface that application code directly uses. +* Handlers send the log records (created by loggers) to the appropriate + destination. +* Filters provide a finer grained facility for determining which log records + to output. +* Formatters specify the layout of log records in the final output. + +Logging is performed by calling methods on instances of the :class:`Logger` +class (hereafter called :dfn:`loggers`). Each instance has a name, and they are +conceptually arranged in a namespace hierarchy using dots (periods) as +separators. For example, a logger named 'scan' is the parent of loggers +'scan.text', 'scan.html' and 'scan.pdf'. Logger names can be anything you want, +and indicate the area of an application in which a logged message originates. + +A good convention to use when naming loggers is to use a module-level logger, +in each module which uses logging, named as follows:: + + logger = logging.getLogger(__name__) + +This means that logger names track the package/module hierarchy, and it's +intuitively obvious where events are logged just from the logger name. + +The root of the hierarchy of loggers is called the root logger. That's the +logger used by the functions :func:`debug`, :func:`info`, :func:`warning`, +:func:`error` and :func:`critical`, which just call the same-named method of +the root logger. The functions and the methods have the same signatures. The +root logger's name is printed as 'root' in the logged output. + +It is, of course, possible to log messages to different destinations. Support +is included in the package for writing log messages to files, HTTP GET/POST +locations, email via SMTP, generic sockets, or OS-specific logging mechanisms +such as syslog or the Windows NT event log. Destinations are served by +:dfn:`handler` classes. You can create your own log destination class if you +have special requirements not met by any of the built-in handler classes. + +By default, no destination is set for any logging messages. You can specify +a destination (such as console or file) by using :func:`basicConfig` as in the +tutorial examples. If you call the functions :func:`debug`, :func:`info`, +:func:`warning`, :func:`error` and :func:`critical`, they will check to see +if no destination is set; and if one is not set, they will set a destination +of the console (``sys.stderr``) and a default format for the displayed +message before delegating to the root logger to do the actual message output. + +The default format set by :func:`basicConfig` for messages is:: + + severity:logger name:message + +You can change this by passing a format string to :func:`basicConfig` with the +*format* keyword argument. For all options regarding how a format string is +constructed, see :ref:`formatter-objects`. + + +Loggers +^^^^^^^ + +:class:`Logger` objects have a threefold job. First, they expose several +methods to application code so that applications can log messages at runtime. +Second, logger objects determine which log messages to act upon based upon +severity (the default filtering facility) or filter objects. Third, logger +objects pass along relevant log messages to all interested log handlers. + +The most widely used methods on logger objects fall into two categories: +configuration and message sending. + +These are the most common configuration methods: + +* :meth:`Logger.setLevel` specifies the lowest-severity log message a logger + will handle, where debug is the lowest built-in severity level and critical + is the highest built-in severity. For example, if the severity level is + INFO, the logger will handle only INFO, WARNING, ERROR, and CRITICAL messages + and will ignore DEBUG messages. + +* :meth:`Logger.addHandler` and :meth:`Logger.removeHandler` add and remove + handler objects from the logger object. Handlers are covered in more detail + in :ref:`handler-basic`. + +* :meth:`Logger.addFilter` and :meth:`Logger.removeFilter` add and remove filter + objects from the logger object. Filters are covered in more detail in + :ref:`filter`. + +You don't need to always call these methods on every logger you create. See the +last two paragraphs in this section. + +With the logger object configured, the following methods create log messages: + +* :meth:`Logger.debug`, :meth:`Logger.info`, :meth:`Logger.warning`, + :meth:`Logger.error`, and :meth:`Logger.critical` all create log records with + a message and a level that corresponds to their respective method names. The + message is actually a format string, which may contain the standard string + substitution syntax of :const:`%s`, :const:`%d`, :const:`%f`, and so on. The + rest of their arguments is a list of objects that correspond with the + substitution fields in the message. With regard to :const:`**kwargs`, the + logging methods care only about a keyword of :const:`exc_info` and use it to + determine whether to log exception information. + +* :meth:`Logger.exception` creates a log message similar to + :meth:`Logger.error`. The difference is that :meth:`Logger.exception` dumps a + stack trace along with it. Call this method only from an exception handler. + +* :meth:`Logger.log` takes a log level as an explicit argument. This is a + little more verbose for logging messages than using the log level convenience + methods listed above, but this is how to log at custom log levels. + +:func:`getLogger` returns a reference to a logger instance with the specified +name if it is provided, or ``root`` if not. The names are period-separated +hierarchical structures. Multiple calls to :func:`getLogger` with the same name +will return a reference to the same logger object. Loggers that are further +down in the hierarchical list are children of loggers higher up in the list. +For example, given a logger with a name of ``foo``, loggers with names of +``foo.bar``, ``foo.bar.baz``, and ``foo.bam`` are all descendants of ``foo``. + +Loggers have a concept of *effective level*. If a level is not explicitly set +on a logger, the level of its parent is used instead as its effective level. +If the parent has no explicit level set, *its* parent is examined, and so on - +all ancestors are searched until an explicitly set level is found. The root +logger always has an explicit level set (``WARNING`` by default). When deciding +whether to process an event, the effective level of the logger is used to +determine whether the event is passed to the logger's handlers. + +Child loggers propagate messages up to the handlers associated with their +ancestor loggers. Because of this, it is unnecessary to define and configure +handlers for all the loggers an application uses. It is sufficient to +configure handlers for a top-level logger and create child loggers as needed. +(You can, however, turn off propagation by setting the *propagate* +attribute of a logger to *False*.) + + +.. _handler-basic: + +Handlers +^^^^^^^^ + +:class:`~logging.Handler` objects are responsible for dispatching the +appropriate log messages (based on the log messages' severity) to the handler's +specified destination. Logger objects can add zero or more handler objects to +themselves with an :func:`addHandler` method. As an example scenario, an +application may want to send all log messages to a log file, all log messages +of error or higher to stdout, and all messages of critical to an email address. +This scenario requires three individual handlers where each handler is +responsible for sending messages of a specific severity to a specific location. + +The standard library includes quite a few handler types (see +:ref:`useful-handlers`); the tutorials use mainly :class:`StreamHandler` and +:class:`FileHandler` in its examples. + +There are very few methods in a handler for application developers to concern +themselves with. The only handler methods that seem relevant for application +developers who are using the built-in handler objects (that is, not creating +custom handlers) are the following configuration methods: + +* The :meth:`Handler.setLevel` method, just as in logger objects, specifies the + lowest severity that will be dispatched to the appropriate destination. Why + are there two :func:`setLevel` methods? The level set in the logger + determines which severity of messages it will pass to its handlers. The level + set in each handler determines which messages that handler will send on. + +* :func:`setFormatter` selects a Formatter object for this handler to use. + +* :func:`addFilter` and :func:`removeFilter` respectively configure and + deconfigure filter objects on handlers. + +Application code should not directly instantiate and use instances of +:class:`Handler`. Instead, the :class:`Handler` class is a base class that +defines the interface that all handlers should have and establishes some +default behavior that child classes can use (or override). + + +Formatters +^^^^^^^^^^ + +Formatter objects configure the final order, structure, and contents of the log +message. Unlike the base :class:`logging.Handler` class, application code may +instantiate formatter classes, although you could likely subclass the formatter +if your application needs special behavior. The constructor takes two +optional arguments -- a message format string and a date format string. + +.. method:: logging.Formatter.__init__(fmt=None, datefmt=None) + +If there is no message format string, the default is to use the +raw message. If there is no date format string, the default date format is:: + + %Y-%m-%d %H:%M:%S + +with the milliseconds tacked on at the end. + +The message format string uses ``%()s`` styled string +substitution; the possible keys are documented in :ref:`logrecord-attributes`. + +The following message format string will log the time in a human-readable +format, the severity of the message, and the contents of the message, in that +order:: + + '%(asctime)s - %(levelname)s - %(message)s' + +Formatters use a user-configurable function to convert the creation time of a +record to a tuple. By default, :func:`time.localtime` is used; to change this +for a particular formatter instance, set the ``converter`` attribute of the +instance to a function with the same signature as :func:`time.localtime` or +:func:`time.gmtime`. To change it for all formatters, for example if you want +all logging times to be shown in GMT, set the ``converter`` attribute in the +Formatter class (to ``time.gmtime`` for GMT display). + + +Configuring Logging +^^^^^^^^^^^^^^^^^^^ + +.. currentmodule:: logging.config + +Programmers can configure logging in three ways: + +1. Creating loggers, handlers, and formatters explicitly using Python + code that calls the configuration methods listed above. +2. Creating a logging config file and reading it using the :func:`fileConfig` + function. +3. Creating a dictionary of configuration information and passing it + to the :func:`dictConfig` function. + +For the reference documentation on the last two options, see +:ref:`logging-config-api`. The following example configures a very simple +logger, a console handler, and a simple formatter using Python code:: + + import logging + + # create logger + logger = logging.getLogger('simple_example') + logger.setLevel(logging.DEBUG) + + # create console handler and set level to debug + ch = logging.StreamHandler() + ch.setLevel(logging.DEBUG) + + # create formatter + formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') + + # add formatter to ch + ch.setFormatter(formatter) + + # add ch to logger + logger.addHandler(ch) + + # 'application' code + logger.debug('debug message') + logger.info('info message') + logger.warn('warn message') + logger.error('error message') + logger.critical('critical message') + +Running this module from the command line produces the following output:: + + $ python simple_logging_module.py + 2005-03-19 15:10:26,618 - simple_example - DEBUG - debug message + 2005-03-19 15:10:26,620 - simple_example - INFO - info message + 2005-03-19 15:10:26,695 - simple_example - WARNING - warn message + 2005-03-19 15:10:26,697 - simple_example - ERROR - error message + 2005-03-19 15:10:26,773 - simple_example - CRITICAL - critical message + +The following Python module creates a logger, handler, and formatter nearly +identical to those in the example listed above, with the only difference being +the names of the objects:: + + import logging + import logging.config + + logging.config.fileConfig('logging.conf') + + # create logger + logger = logging.getLogger('simpleExample') + + # 'application' code + logger.debug('debug message') + logger.info('info message') + logger.warn('warn message') + logger.error('error message') + logger.critical('critical message') + +Here is the logging.conf file:: + + [loggers] + keys=root,simpleExample + + [handlers] + keys=consoleHandler + + [formatters] + keys=simpleFormatter + + [logger_root] + level=DEBUG + handlers=consoleHandler + + [logger_simpleExample] + level=DEBUG + handlers=consoleHandler + qualname=simpleExample + propagate=0 + + [handler_consoleHandler] + class=StreamHandler + level=DEBUG + formatter=simpleFormatter + args=(sys.stdout,) + + [formatter_simpleFormatter] + format=%(asctime)s - %(name)s - %(levelname)s - %(message)s + datefmt= + +The output is nearly identical to that of the non-config-file-based example:: + + $ python simple_logging_config.py + 2005-03-19 15:38:55,977 - simpleExample - DEBUG - debug message + 2005-03-19 15:38:55,979 - simpleExample - INFO - info message + 2005-03-19 15:38:56,054 - simpleExample - WARNING - warn message + 2005-03-19 15:38:56,055 - simpleExample - ERROR - error message + 2005-03-19 15:38:56,130 - simpleExample - CRITICAL - critical message + +You can see that the config file approach has a few advantages over the Python +code approach, mainly separation of configuration and code and the ability of +noncoders to easily modify the logging properties. + +.. currentmodule:: logging + +Note that the class names referenced in config files need to be either relative +to the logging module, or absolute values which can be resolved using normal +import mechanisms. Thus, you could use either +:class:`~logging.handlers.WatchedFileHandler` (relative to the logging module) or +``mypackage.mymodule.MyHandler`` (for a class defined in package ``mypackage`` +and module ``mymodule``, where ``mypackage`` is available on the Python import +path). + +In Python 2.7, a new means of configuring logging has been introduced, using +dictionaries to hold configuration information. This provides a superset of the +functionality of the config-file-based approach outlined above, and is the +recommended configuration method for new applications and deployments. Because +a Python dictionary is used to hold configuration information, and since you +can populate that dictionary using different means, you have more options for +configuration. For example, you can use a configuration file in JSON format, +or, if you have access to YAML processing functionality, a file in YAML +format, to populate the configuration dictionary. Or, of course, you can +construct the dictionary in Python code, receive it in pickled form over a +socket, or use whatever approach makes sense for your application. + +Here's an example of the same configuration as above, in YAML format for +the new dictionary-based approach:: + + version: 1 + formatters: + simple: + format: format=%(asctime)s - %(name)s - %(levelname)s - %(message)s + handlers: + console: + class: logging.StreamHandler + level: DEBUG + formatter: simple + stream: ext://sys.stdout + loggers: + simpleExample: + level: DEBUG + handlers: [console] + propagate: no + root: + level: DEBUG + handlers: [console] + +For more information about logging using a dictionary, see +:ref:`logging-config-api`. + +What happens if no configuration is provided +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +If no logging configuration is provided, it is possible to have a situation +where a logging event needs to be output, but no handlers can be found to +output the event. The behaviour of the logging package in these +circumstances is dependent on the Python version. + +For Python 2.x, the behaviour is as follows: + +* If *logging.raiseExceptions* is *False* (production mode), the event is + silently dropped. + +* If *logging.raiseExceptions* is *True* (development mode), a message + 'No handlers could be found for logger X.Y.Z' is printed once. + +.. _library-config: + +Configuring Logging for a Library +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +When developing a library which uses logging, you should take care to +document how the library uses logging - for example, the names of loggers +used. Some consideration also needs to be given to its logging configuration. +If the using application does not use logging, and library code makes logging +calls, then (as described in the previous section) events of severity +``WARNING`` and greater will be printed to ``sys.stderr``. This is regarded as +the best default behaviour. + +If for some reason you *don't* want these messages printed in the absence of +any logging configuration, you can attach a do-nothing handler to the top-level +logger for your library. This avoids the message being printed, since a handler +will be always be found for the library's events: it just doesn't produce any +output. If the library user configures logging for application use, presumably +that configuration will add some handlers, and if levels are suitably +configured then logging calls made in library code will send output to those +handlers, as normal. + +A do-nothing handler is included in the logging package: +:class:`~logging.NullHandler` (since Python 2.7). An instance of this handler +could be added to the top-level logger of the logging namespace used by the +library (*if* you want to prevent your library's logged events being output to +``sys.stderr`` in the absence of logging configuration). If all logging by a +library *foo* is done using loggers with names matching 'foo.x', 'foo.x.y', +etc. then the code:: + + import logging + logging.getLogger('foo').addHandler(logging.NullHandler()) + +should have the desired effect. If an organisation produces a number of +libraries, then the logger name specified can be 'orgname.foo' rather than +just 'foo'. + +**PLEASE NOTE:** It is strongly advised that you *do not add any handlers other +than* :class:`~logging.NullHandler` *to your library's loggers*. This is +because the configuration of handlers is the prerogative of the application +developer who uses your library. The application developer knows their target +audience and what handlers are most appropriate for their application: if you +add handlers 'under the hood', you might well interfere with their ability to +carry out unit tests and deliver logs which suit their requirements. + + +Logging Levels +-------------- + +The numeric values of logging levels are given in the following table. These are +primarily of interest if you want to define your own levels, and need them to +have specific values relative to the predefined levels. If you define a level +with the same numeric value, it overwrites the predefined value; the predefined +name is lost. + ++--------------+---------------+ +| Level | Numeric value | ++==============+===============+ +| ``CRITICAL`` | 50 | ++--------------+---------------+ +| ``ERROR`` | 40 | ++--------------+---------------+ +| ``WARNING`` | 30 | ++--------------+---------------+ +| ``INFO`` | 20 | ++--------------+---------------+ +| ``DEBUG`` | 10 | ++--------------+---------------+ +| ``NOTSET`` | 0 | ++--------------+---------------+ + +Levels can also be associated with loggers, being set either by the developer or +through loading a saved logging configuration. When a logging method is called +on a logger, the logger compares its own level with the level associated with +the method call. If the logger's level is higher than the method call's, no +logging message is actually generated. This is the basic mechanism controlling +the verbosity of logging output. + +Logging messages are encoded as instances of the :class:`~logging.LogRecord` +class. When a logger decides to actually log an event, a +:class:`~logging.LogRecord` instance is created from the logging message. + +Logging messages are subjected to a dispatch mechanism through the use of +:dfn:`handlers`, which are instances of subclasses of the :class:`Handler` +class. Handlers are responsible for ensuring that a logged message (in the form +of a :class:`LogRecord`) ends up in a particular location (or set of locations) +which is useful for the target audience for that message (such as end users, +support desk staff, system administrators, developers). Handlers are passed +:class:`LogRecord` instances intended for particular destinations. Each logger +can have zero, one or more handlers associated with it (via the +:meth:`~Logger.addHandler` method of :class:`Logger`). In addition to any +handlers directly associated with a logger, *all handlers associated with all +ancestors of the logger* are called to dispatch the message (unless the +*propagate* flag for a logger is set to a false value, at which point the +passing to ancestor handlers stops). + +Just as for loggers, handlers can have levels associated with them. A handler's +level acts as a filter in the same way as a logger's level does. If a handler +decides to actually dispatch an event, the :meth:`~Handler.emit` method is used +to send the message to its destination. Most user-defined subclasses of +:class:`Handler` will need to override this :meth:`~Handler.emit`. + +.. _custom-levels: + +Custom Levels +^^^^^^^^^^^^^ + +Defining your own levels is possible, but should not be necessary, as the +existing levels have been chosen on the basis of practical experience. +However, if you are convinced that you need custom levels, great care should +be exercised when doing this, and it is possibly *a very bad idea to define +custom levels if you are developing a library*. That's because if multiple +library authors all define their own custom levels, there is a chance that +the logging output from such multiple libraries used together will be +difficult for the using developer to control and/or interpret, because a +given numeric value might mean different things for different libraries. + +.. _useful-handlers: + +Useful Handlers +--------------- + +In addition to the base :class:`Handler` class, many useful subclasses are +provided: + +#. :class:`StreamHandler` instances send messages to streams (file-like + objects). + +#. :class:`FileHandler` instances send messages to disk files. + +#. :class:`~handlers.BaseRotatingHandler` is the base class for handlers that + rotate log files at a certain point. It is not meant to be instantiated + directly. Instead, use :class:`~handlers.RotatingFileHandler` or + :class:`~handlers.TimedRotatingFileHandler`. + +#. :class:`~handlers.RotatingFileHandler` instances send messages to disk + files, with support for maximum log file sizes and log file rotation. + +#. :class:`~handlers.TimedRotatingFileHandler` instances send messages to + disk files, rotating the log file at certain timed intervals. + +#. :class:`~handlers.SocketHandler` instances send messages to TCP/IP + sockets. + +#. :class:`~handlers.DatagramHandler` instances send messages to UDP + sockets. + +#. :class:`~handlers.SMTPHandler` instances send messages to a designated + email address. + +#. :class:`~handlers.SysLogHandler` instances send messages to a Unix + syslog daemon, possibly on a remote machine. + +#. :class:`~handlers.NTEventLogHandler` instances send messages to a + Windows NT/2000/XP event log. + +#. :class:`~handlers.MemoryHandler` instances send messages to a buffer + in memory, which is flushed whenever specific criteria are met. + +#. :class:`~handlers.HTTPHandler` instances send messages to an HTTP + server using either ``GET`` or ``POST`` semantics. + +#. :class:`~handlers.WatchedFileHandler` instances watch the file they are + logging to. If the file changes, it is closed and reopened using the file + name. This handler is only useful on Unix-like systems; Windows does not + support the underlying mechanism used. + +#. :class:`NullHandler` instances do nothing with error messages. They are used + by library developers who want to use logging, but want to avoid the 'No + handlers could be found for logger XXX' message which can be displayed if + the library user has not configured logging. See :ref:`library-config` for + more information. + +.. versionadded:: 2.7 + The :class:`NullHandler` class. + +The :class:`NullHandler`, :class:`StreamHandler` and :class:`FileHandler` +classes are defined in the core logging package. The other handlers are +defined in a sub- module, :mod:`logging.handlers`. (There is also another +sub-module, :mod:`logging.config`, for configuration functionality.) + +Logged messages are formatted for presentation through instances of the +:class:`Formatter` class. They are initialized with a format string suitable for +use with the % operator and a dictionary. + +For formatting multiple messages in a batch, instances of +:class:`BufferingFormatter` can be used. In addition to the format string (which +is applied to each message in the batch), there is provision for header and +trailer format strings. + +When filtering based on logger level and/or handler level is not enough, +instances of :class:`Filter` can be added to both :class:`Logger` and +:class:`Handler` instances (through their :meth:`addFilter` method). Before +deciding to process a message further, both loggers and handlers consult all +their filters for permission. If any filter returns a false value, the message +is not processed further. + +The basic :class:`Filter` functionality allows filtering by specific logger +name. If this feature is used, messages sent to the named logger and its +children are allowed through the filter, and all others dropped. + + +.. _logging-exceptions: + +Exceptions raised during logging +-------------------------------- + +The logging package is designed to swallow exceptions which occur while logging +in production. This is so that errors which occur while handling logging events +- such as logging misconfiguration, network or other similar errors - do not +cause the application using logging to terminate prematurely. + +:class:`SystemExit` and :class:`KeyboardInterrupt` exceptions are never +swallowed. Other exceptions which occur during the :meth:`emit` method of a +:class:`Handler` subclass are passed to its :meth:`handleError` method. + +The default implementation of :meth:`handleError` in :class:`Handler` checks +to see if a module-level variable, :data:`raiseExceptions`, is set. If set, a +traceback is printed to :data:`sys.stderr`. If not set, the exception is swallowed. + +**Note:** The default value of :data:`raiseExceptions` is ``True``. This is because +during development, you typically want to be notified of any exceptions that +occur. It's advised that you set :data:`raiseExceptions` to ``False`` for production +usage. + +.. currentmodule:: logging + +.. _arbitrary-object-messages: + +Using arbitrary objects as messages +----------------------------------- + +In the preceding sections and examples, it has been assumed that the message +passed when logging the event is a string. However, this is not the only +possibility. You can pass an arbitrary object as a message, and its +:meth:`__str__` method will be called when the logging system needs to convert +it to a string representation. In fact, if you want to, you can avoid +computing a string representation altogether - for example, the +:class:`SocketHandler` emits an event by pickling it and sending it over the +wire. + + +Optimization +------------ + +Formatting of message arguments is deferred until it cannot be avoided. +However, computing the arguments passed to the logging method can also be +expensive, and you may want to avoid doing it if the logger will just throw +away your event. To decide what to do, you can call the :meth:`isEnabledFor` +method which takes a level argument and returns true if the event would be +created by the Logger for that level of call. You can write code like this:: + + if logger.isEnabledFor(logging.DEBUG): + logger.debug('Message with %s, %s', expensive_func1(), + expensive_func2()) + +so that if the logger's threshold is set above ``DEBUG``, the calls to +:func:`expensive_func1` and :func:`expensive_func2` are never made. + +There are other optimizations which can be made for specific applications which +need more precise control over what logging information is collected. Here's a +list of things you can do to avoid processing during logging which you don't +need: + ++-----------------------------------------------+----------------------------------------+ +| What you don't want to collect | How to avoid collecting it | ++===============================================+========================================+ +| Information about where calls were made from. | Set ``logging._srcfile`` to ``None``. | ++-----------------------------------------------+----------------------------------------+ +| Threading information. | Set ``logging.logThreads`` to ``0``. | ++-----------------------------------------------+----------------------------------------+ +| Process information. | Set ``logging.logProcesses`` to ``0``. | ++-----------------------------------------------+----------------------------------------+ + +Also note that the core logging module only includes the basic handlers. If +you don't import :mod:`logging.handlers` and :mod:`logging.config`, they won't +take up any memory. + +.. seealso:: + + Module :mod:`logging` + API reference for the logging module. + + Module :mod:`logging.config` + Configuration API for the logging module. + + Module :mod:`logging.handlers` + Useful handlers included with the logging module. + + :ref:`A logging cookbook ` + diff --git a/Doc/library/allos.rst b/Doc/library/allos.rst --- a/Doc/library/allos.rst +++ b/Doc/library/allos.rst @@ -20,6 +20,8 @@ optparse.rst getopt.rst logging.rst + logging.config.rst + logging.handlers.rst getpass.rst curses.rst curses.ascii.rst diff --git a/Doc/library/logging.config.rst b/Doc/library/logging.config.rst new file mode 100644 --- /dev/null +++ b/Doc/library/logging.config.rst @@ -0,0 +1,673 @@ +:mod:`logging.config` --- Logging configuration +=============================================== + +.. module:: logging.config + :synopsis: Configuration of the logging module. + + +.. moduleauthor:: Vinay Sajip +.. sectionauthor:: Vinay Sajip + +.. sidebar:: Important + + This page contains only reference information. For tutorials, + please see + + * :ref:`Basic Tutorial ` + * :ref:`Advanced Tutorial ` + * :ref:`Logging Cookbook ` + +This section describes the API for configuring the logging module. + +.. _logging-config-api: + +Configuration functions +^^^^^^^^^^^^^^^^^^^^^^^ + +The following functions configure the logging module. They are located in the +:mod:`logging.config` module. Their use is optional --- you can configure the +logging module using these functions or by making calls to the main API (defined +in :mod:`logging` itself) and defining handlers which are declared either in +:mod:`logging` or :mod:`logging.handlers`. + +.. function:: dictConfig(config) + + Takes the logging configuration from a dictionary. The contents of + this dictionary are described in :ref:`logging-config-dictschema` + below. + + If an error is encountered during configuration, this function will + raise a :exc:`ValueError`, :exc:`TypeError`, :exc:`AttributeError` + or :exc:`ImportError` with a suitably descriptive message. The + following is a (possibly incomplete) list of conditions which will + raise an error: + + * A ``level`` which is not a string or which is a string not + corresponding to an actual logging level. + * A ``propagate`` value which is not a boolean. + * An id which does not have a corresponding destination. + * A non-existent handler id found during an incremental call. + * An invalid logger name. + * Inability to resolve to an internal or external object. + + Parsing is performed by the :class:`DictConfigurator` class, whose + constructor is passed the dictionary used for configuration, and + has a :meth:`configure` method. The :mod:`logging.config` module + has a callable attribute :attr:`dictConfigClass` + which is initially set to :class:`DictConfigurator`. + You can replace the value of :attr:`dictConfigClass` with a + suitable implementation of your own. + + :func:`dictConfig` calls :attr:`dictConfigClass` passing + the specified dictionary, and then calls the :meth:`configure` method on + the returned object to put the configuration into effect:: + + def dictConfig(config): + dictConfigClass(config).configure() + + For example, a subclass of :class:`DictConfigurator` could call + ``DictConfigurator.__init__()`` in its own :meth:`__init__()`, then + set up custom prefixes which would be usable in the subsequent + :meth:`configure` call. :attr:`dictConfigClass` would be bound to + this new subclass, and then :func:`dictConfig` could be called exactly as + in the default, uncustomized state. + + .. versionadded:: 2.7 + +.. function:: fileConfig(fname[, defaults]) + + Reads the logging configuration from a :mod:`configparser`\-format file named + *fname*. This function can be called several times from an application, + allowing an end user to select from various pre-canned + configurations (if the developer provides a mechanism to present the choices + and load the chosen configuration). Defaults to be passed to the ConfigParser + can be specified in the *defaults* argument. + + +.. function:: listen(port=DEFAULT_LOGGING_CONFIG_PORT) + + Starts up a socket server on the specified port, and listens for new + configurations. If no port is specified, the module's default + :const:`DEFAULT_LOGGING_CONFIG_PORT` is used. Logging configurations will be + sent as a file suitable for processing by :func:`fileConfig`. Returns a + :class:`Thread` instance on which you can call :meth:`start` to start the + server, and which you can :meth:`join` when appropriate. To stop the server, + call :func:`stopListening`. + + To send a configuration to the socket, read in the configuration file and + send it to the socket as a string of bytes preceded by a four-byte length + string packed in binary using ``struct.pack('>L', n)``. + + +.. function:: stopListening() + + Stops the listening server which was created with a call to :func:`listen`. + This is typically called before calling :meth:`join` on the return value from + :func:`listen`. + + +.. _logging-config-dictschema: + +Configuration dictionary schema +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Describing a logging configuration requires listing the various +objects to create and the connections between them; for example, you +may create a handler named 'console' and then say that the logger +named 'startup' will send its messages to the 'console' handler. +These objects aren't limited to those provided by the :mod:`logging` +module because you might write your own formatter or handler class. +The parameters to these classes may also need to include external +objects such as ``sys.stderr``. The syntax for describing these +objects and connections is defined in :ref:`logging-config-dict-connections` +below. + +Dictionary Schema Details +""""""""""""""""""""""""" + +The dictionary passed to :func:`dictConfig` must contain the following +keys: + +* *version* - to be set to an integer value representing the schema + version. The only valid value at present is 1, but having this key + allows the schema to evolve while still preserving backwards + compatibility. + +All other keys are optional, but if present they will be interpreted +as described below. In all cases below where a 'configuring dict' is +mentioned, it will be checked for the special ``'()'`` key to see if a +custom instantiation is required. If so, the mechanism described in +:ref:`logging-config-dict-userdef` below is used to create an instance; +otherwise, the context is used to determine what to instantiate. + +* *formatters* - the corresponding value will be a dict in which each + key is a formatter id and each value is a dict describing how to + configure the corresponding Formatter instance. + + The configuring dict is searched for keys ``format`` and ``datefmt`` + (with defaults of ``None``) and these are used to construct a + :class:`logging.Formatter` instance. + +* *filters* - the corresponding value will be a dict in which each key + is a filter id and each value is a dict describing how to configure + the corresponding Filter instance. + + The configuring dict is searched for the key ``name`` (defaulting to the + empty string) and this is used to construct a :class:`logging.Filter` + instance. + +* *handlers* - the corresponding value will be a dict in which each + key is a handler id and each value is a dict describing how to + configure the corresponding Handler instance. + + The configuring dict is searched for the following keys: + + * ``class`` (mandatory). This is the fully qualified name of the + handler class. + + * ``level`` (optional). The level of the handler. + + * ``formatter`` (optional). The id of the formatter for this + handler. + + * ``filters`` (optional). A list of ids of the filters for this + handler. + + All *other* keys are passed through as keyword arguments to the + handler's constructor. For example, given the snippet:: + + handlers: + console: + class : logging.StreamHandler + formatter: brief + level : INFO + filters: [allow_foo] + stream : ext://sys.stdout + file: + class : logging.handlers.RotatingFileHandler + formatter: precise + filename: logconfig.log + maxBytes: 1024 + backupCount: 3 + + the handler with id ``console`` is instantiated as a + :class:`logging.StreamHandler`, using ``sys.stdout`` as the underlying + stream. The handler with id ``file`` is instantiated as a + :class:`logging.handlers.RotatingFileHandler` with the keyword arguments + ``filename='logconfig.log', maxBytes=1024, backupCount=3``. + +* *loggers* - the corresponding value will be a dict in which each key + is a logger name and each value is a dict describing how to + configure the corresponding Logger instance. + + The configuring dict is searched for the following keys: + + * ``level`` (optional). The level of the logger. + + * ``propagate`` (optional). The propagation setting of the logger. + + * ``filters`` (optional). A list of ids of the filters for this + logger. + + * ``handlers`` (optional). A list of ids of the handlers for this + logger. + + The specified loggers will be configured according to the level, + propagation, filters and handlers specified. + +* *root* - this will be the configuration for the root logger. + Processing of the configuration will be as for any logger, except + that the ``propagate`` setting will not be applicable. + +* *incremental* - whether the configuration is to be interpreted as + incremental to the existing configuration. This value defaults to + ``False``, which means that the specified configuration replaces the + existing configuration with the same semantics as used by the + existing :func:`fileConfig` API. + + If the specified value is ``True``, the configuration is processed + as described in the section on :ref:`logging-config-dict-incremental`. + +* *disable_existing_loggers* - whether any existing loggers are to be + disabled. This setting mirrors the parameter of the same name in + :func:`fileConfig`. If absent, this parameter defaults to ``True``. + This value is ignored if *incremental* is ``True``. + +.. _logging-config-dict-incremental: + +Incremental Configuration +""""""""""""""""""""""""" + +It is difficult to provide complete flexibility for incremental +configuration. For example, because objects such as filters +and formatters are anonymous, once a configuration is set up, it is +not possible to refer to such anonymous objects when augmenting a +configuration. + +Furthermore, there is not a compelling case for arbitrarily altering +the object graph of loggers, handlers, filters, formatters at +run-time, once a configuration is set up; the verbosity of loggers and +handlers can be controlled just by setting levels (and, in the case of +loggers, propagation flags). Changing the object graph arbitrarily in +a safe way is problematic in a multi-threaded environment; while not +impossible, the benefits are not worth the complexity it adds to the +implementation. + +Thus, when the ``incremental`` key of a configuration dict is present +and is ``True``, the system will completely ignore any ``formatters`` and +``filters`` entries, and process only the ``level`` +settings in the ``handlers`` entries, and the ``level`` and +``propagate`` settings in the ``loggers`` and ``root`` entries. + +Using a value in the configuration dict lets configurations to be sent +over the wire as pickled dicts to a socket listener. Thus, the logging +verbosity of a long-running application can be altered over time with +no need to stop and restart the application. + +.. _logging-config-dict-connections: + +Object connections +"""""""""""""""""" + +The schema describes a set of logging objects - loggers, +handlers, formatters, filters - which are connected to each other in +an object graph. Thus, the schema needs to represent connections +between the objects. For example, say that, once configured, a +particular logger has attached to it a particular handler. For the +purposes of this discussion, we can say that the logger represents the +source, and the handler the destination, of a connection between the +two. Of course in the configured objects this is represented by the +logger holding a reference to the handler. In the configuration dict, +this is done by giving each destination object an id which identifies +it unambiguously, and then using the id in the source object's +configuration to indicate that a connection exists between the source +and the destination object with that id. + +So, for example, consider the following YAML snippet:: + + formatters: + brief: + # configuration for formatter with id 'brief' goes here + precise: + # configuration for formatter with id 'precise' goes here + handlers: + h1: #This is an id + # configuration of handler with id 'h1' goes here + formatter: brief + h2: #This is another id + # configuration of handler with id 'h2' goes here + formatter: precise + loggers: + foo.bar.baz: + # other configuration for logger 'foo.bar.baz' + handlers: [h1, h2] + +(Note: YAML used here because it's a little more readable than the +equivalent Python source form for the dictionary.) + +The ids for loggers are the logger names which would be used +programmatically to obtain a reference to those loggers, e.g. +``foo.bar.baz``. The ids for Formatters and Filters can be any string +value (such as ``brief``, ``precise`` above) and they are transient, +in that they are only meaningful for processing the configuration +dictionary and used to determine connections between objects, and are +not persisted anywhere when the configuration call is complete. + +The above snippet indicates that logger named ``foo.bar.baz`` should +have two handlers attached to it, which are described by the handler +ids ``h1`` and ``h2``. The formatter for ``h1`` is that described by id +``brief``, and the formatter for ``h2`` is that described by id +``precise``. + + +.. _logging-config-dict-userdef: + +User-defined objects +"""""""""""""""""""" + +The schema supports user-defined objects for handlers, filters and +formatters. (Loggers do not need to have different types for +different instances, so there is no support in this configuration +schema for user-defined logger classes.) + +Objects to be configured are described by dictionaries +which detail their configuration. In some places, the logging system +will be able to infer from the context how an object is to be +instantiated, but when a user-defined object is to be instantiated, +the system will not know how to do this. In order to provide complete +flexibility for user-defined object instantiation, the user needs +to provide a 'factory' - a callable which is called with a +configuration dictionary and which returns the instantiated object. +This is signalled by an absolute import path to the factory being +made available under the special key ``'()'``. Here's a concrete +example:: + + formatters: + brief: + format: '%(message)s' + default: + format: '%(asctime)s %(levelname)-8s %(name)-15s %(message)s' + datefmt: '%Y-%m-%d %H:%M:%S' + custom: + (): my.package.customFormatterFactory + bar: baz + spam: 99.9 + answer: 42 + +The above YAML snippet defines three formatters. The first, with id +``brief``, is a standard :class:`logging.Formatter` instance with the +specified format string. The second, with id ``default``, has a +longer format and also defines the time format explicitly, and will +result in a :class:`logging.Formatter` initialized with those two format +strings. Shown in Python source form, the ``brief`` and ``default`` +formatters have configuration sub-dictionaries:: + + { + 'format' : '%(message)s' + } + +and:: + + { + 'format' : '%(asctime)s %(levelname)-8s %(name)-15s %(message)s', + 'datefmt' : '%Y-%m-%d %H:%M:%S' + } + +respectively, and as these dictionaries do not contain the special key +``'()'``, the instantiation is inferred from the context: as a result, +standard :class:`logging.Formatter` instances are created. The +configuration sub-dictionary for the third formatter, with id +``custom``, is:: + + { + '()' : 'my.package.customFormatterFactory', + 'bar' : 'baz', + 'spam' : 99.9, + 'answer' : 42 + } + +and this contains the special key ``'()'``, which means that +user-defined instantiation is wanted. In this case, the specified +factory callable will be used. If it is an actual callable it will be +used directly - otherwise, if you specify a string (as in the example) +the actual callable will be located using normal import mechanisms. +The callable will be called with the **remaining** items in the +configuration sub-dictionary as keyword arguments. In the above +example, the formatter with id ``custom`` will be assumed to be +returned by the call:: + + my.package.customFormatterFactory(bar='baz', spam=99.9, answer=42) + +The key ``'()'`` has been used as the special key because it is not a +valid keyword parameter name, and so will not clash with the names of +the keyword arguments used in the call. The ``'()'`` also serves as a +mnemonic that the corresponding value is a callable. + + +.. _logging-config-dict-externalobj: + +Access to external objects +"""""""""""""""""""""""""" + +There are times where a configuration needs to refer to objects +external to the configuration, for example ``sys.stderr``. If the +configuration dict is constructed using Python code, this is +straightforward, but a problem arises when the configuration is +provided via a text file (e.g. JSON, YAML). In a text file, there is +no standard way to distinguish ``sys.stderr`` from the literal string +``'sys.stderr'``. To facilitate this distinction, the configuration +system looks for certain special prefixes in string values and +treat them specially. For example, if the literal string +``'ext://sys.stderr'`` is provided as a value in the configuration, +then the ``ext://`` will be stripped off and the remainder of the +value processed using normal import mechanisms. + +The handling of such prefixes is done in a way analogous to protocol +handling: there is a generic mechanism to look for prefixes which +match the regular expression ``^(?P[a-z]+)://(?P.*)$`` +whereby, if the ``prefix`` is recognised, the ``suffix`` is processed +in a prefix-dependent manner and the result of the processing replaces +the string value. If the prefix is not recognised, then the string +value will be left as-is. + + +.. _logging-config-dict-internalobj: + +Access to internal objects +"""""""""""""""""""""""""" + +As well as external objects, there is sometimes also a need to refer +to objects in the configuration. This will be done implicitly by the +configuration system for things that it knows about. For example, the +string value ``'DEBUG'`` for a ``level`` in a logger or handler will +automatically be converted to the value ``logging.DEBUG``, and the +``handlers``, ``filters`` and ``formatter`` entries will take an +object id and resolve to the appropriate destination object. + +However, a more generic mechanism is needed for user-defined +objects which are not known to the :mod:`logging` module. For +example, consider :class:`logging.handlers.MemoryHandler`, which takes +a ``target`` argument which is another handler to delegate to. Since +the system already knows about this class, then in the configuration, +the given ``target`` just needs to be the object id of the relevant +target handler, and the system will resolve to the handler from the +id. If, however, a user defines a ``my.package.MyHandler`` which has +an ``alternate`` handler, the configuration system would not know that +the ``alternate`` referred to a handler. To cater for this, a generic +resolution system allows the user to specify:: + + handlers: + file: + # configuration of file handler goes here + + custom: + (): my.package.MyHandler + alternate: cfg://handlers.file + +The literal string ``'cfg://handlers.file'`` will be resolved in an +analogous way to strings with the ``ext://`` prefix, but looking +in the configuration itself rather than the import namespace. The +mechanism allows access by dot or by index, in a similar way to +that provided by ``str.format``. Thus, given the following snippet:: + + handlers: + email: + class: logging.handlers.SMTPHandler + mailhost: localhost + fromaddr: my_app at domain.tld + toaddrs: + - support_team at domain.tld + - dev_team at domain.tld + subject: Houston, we have a problem. + +in the configuration, the string ``'cfg://handlers'`` would resolve to +the dict with key ``handlers``, the string ``'cfg://handlers.email`` +would resolve to the dict with key ``email`` in the ``handlers`` dict, +and so on. The string ``'cfg://handlers.email.toaddrs[1]`` would +resolve to ``'dev_team.domain.tld'`` and the string +``'cfg://handlers.email.toaddrs[0]'`` would resolve to the value +``'support_team at domain.tld'``. The ``subject`` value could be accessed +using either ``'cfg://handlers.email.subject'`` or, equivalently, +``'cfg://handlers.email[subject]'``. The latter form only needs to be +used if the key contains spaces or non-alphanumeric characters. If an +index value consists only of decimal digits, access will be attempted +using the corresponding integer value, falling back to the string +value if needed. + +Given a string ``cfg://handlers.myhandler.mykey.123``, this will +resolve to ``config_dict['handlers']['myhandler']['mykey']['123']``. +If the string is specified as ``cfg://handlers.myhandler.mykey[123]``, +the system will attempt to retrieve the value from +``config_dict['handlers']['myhandler']['mykey'][123]``, and fall back +to ``config_dict['handlers']['myhandler']['mykey']['123']`` if that +fails. + +.. _logging-config-fileformat: + +Configuration file format +^^^^^^^^^^^^^^^^^^^^^^^^^ + +The configuration file format understood by :func:`fileConfig` is based on +:mod:`configparser` functionality. The file must contain sections called +``[loggers]``, ``[handlers]`` and ``[formatters]`` which identify by name the +entities of each type which are defined in the file. For each such entity, there +is a separate section which identifies how that entity is configured. Thus, for +a logger named ``log01`` in the ``[loggers]`` section, the relevant +configuration details are held in a section ``[logger_log01]``. Similarly, a +handler called ``hand01`` in the ``[handlers]`` section will have its +configuration held in a section called ``[handler_hand01]``, while a formatter +called ``form01`` in the ``[formatters]`` section will have its configuration +specified in a section called ``[formatter_form01]``. The root logger +configuration must be specified in a section called ``[logger_root]``. + +Examples of these sections in the file are given below. :: + + [loggers] + keys=root,log02,log03,log04,log05,log06,log07 + + [handlers] + keys=hand01,hand02,hand03,hand04,hand05,hand06,hand07,hand08,hand09 + + [formatters] + keys=form01,form02,form03,form04,form05,form06,form07,form08,form09 + +The root logger must specify a level and a list of handlers. An example of a +root logger section is given below. :: + + [logger_root] + level=NOTSET + handlers=hand01 + +The ``level`` entry can be one of ``DEBUG, INFO, WARNING, ERROR, CRITICAL`` or +``NOTSET``. For the root logger only, ``NOTSET`` means that all messages will be +logged. Level values are :func:`eval`\ uated in the context of the ``logging`` +package's namespace. + +The ``handlers`` entry is a comma-separated list of handler names, which must +appear in the ``[handlers]`` section. These names must appear in the +``[handlers]`` section and have corresponding sections in the configuration +file. + +For loggers other than the root logger, some additional information is required. +This is illustrated by the following example. :: + + [logger_parser] + level=DEBUG + handlers=hand01 + propagate=1 + qualname=compiler.parser + +The ``level`` and ``handlers`` entries are interpreted as for the root logger, +except that if a non-root logger's level is specified as ``NOTSET``, the system +consults loggers higher up the hierarchy to determine the effective level of the +logger. The ``propagate`` entry is set to 1 to indicate that messages must +propagate to handlers higher up the logger hierarchy from this logger, or 0 to +indicate that messages are **not** propagated to handlers up the hierarchy. The +``qualname`` entry is the hierarchical channel name of the logger, that is to +say the name used by the application to get the logger. + +Sections which specify handler configuration are exemplified by the following. +:: + + [handler_hand01] + class=StreamHandler + level=NOTSET + formatter=form01 + args=(sys.stdout,) + +The ``class`` entry indicates the handler's class (as determined by :func:`eval` +in the ``logging`` package's namespace). The ``level`` is interpreted as for +loggers, and ``NOTSET`` is taken to mean 'log everything'. + +.. versionchanged:: 2.6 + Added support for resolving the handler?s class as a dotted module and + class name. + +The ``formatter`` entry indicates the key name of the formatter for this +handler. If blank, a default formatter (``logging._defaultFormatter``) is used. +If a name is specified, it must appear in the ``[formatters]`` section and have +a corresponding section in the configuration file. + +The ``args`` entry, when :func:`eval`\ uated in the context of the ``logging`` +package's namespace, is the list of arguments to the constructor for the handler +class. Refer to the constructors for the relevant handlers, or to the examples +below, to see how typical entries are constructed. :: + + [handler_hand02] + class=FileHandler + level=DEBUG + formatter=form02 + args=('python.log', 'w') + + [handler_hand03] + class=handlers.SocketHandler + level=INFO + formatter=form03 + args=('localhost', handlers.DEFAULT_TCP_LOGGING_PORT) + + [handler_hand04] + class=handlers.DatagramHandler + level=WARN + formatter=form04 + args=('localhost', handlers.DEFAULT_UDP_LOGGING_PORT) + + [handler_hand05] + class=handlers.SysLogHandler + level=ERROR + formatter=form05 + args=(('localhost', handlers.SYSLOG_UDP_PORT), handlers.SysLogHandler.LOG_USER) + + [handler_hand06] + class=handlers.NTEventLogHandler + level=CRITICAL + formatter=form06 + args=('Python Application', '', 'Application') + + [handler_hand07] + class=handlers.SMTPHandler + level=WARN + formatter=form07 + args=('localhost', 'from at abc', ['user1 at abc', 'user2 at xyz'], 'Logger Subject') + + [handler_hand08] + class=handlers.MemoryHandler + level=NOTSET + formatter=form08 + target= + args=(10, ERROR) + + [handler_hand09] + class=handlers.HTTPHandler + level=NOTSET + formatter=form09 + args=('localhost:9022', '/log', 'GET') + +Sections which specify formatter configuration are typified by the following. :: + + [formatter_form01] + format=F1 %(asctime)s %(levelname)s %(message)s + datefmt= + class=logging.Formatter + +The ``format`` entry is the overall format string, and the ``datefmt`` entry is +the :func:`strftime`\ -compatible date/time format string. If empty, the +package substitutes ISO8601 format date/times, which is almost equivalent to +specifying the date format string ``'%Y-%m-%d %H:%M:%S'``. The ISO8601 format +also specifies milliseconds, which are appended to the result of using the above +format string, with a comma separator. An example time in ISO8601 format is +``2003-01-23 00:29:50,411``. + +The ``class`` entry is optional. It indicates the name of the formatter's class +(as a dotted module and class name.) This option is useful for instantiating a +:class:`Formatter` subclass. Subclasses of :class:`Formatter` can present +exception tracebacks in an expanded or condensed format. + +.. seealso:: + + Module :mod:`logging` + API reference for the logging module. + + Module :mod:`logging.handlers` + Useful handlers included with the logging module. + + diff --git a/Doc/library/logging.handlers.rst b/Doc/library/logging.handlers.rst new file mode 100644 --- /dev/null +++ b/Doc/library/logging.handlers.rst @@ -0,0 +1,740 @@ +:mod:`logging.handlers` --- Logging handlers +============================================ + +.. module:: logging.handlers + :synopsis: Handlers for the logging module. + + +.. moduleauthor:: Vinay Sajip +.. sectionauthor:: Vinay Sajip + +.. sidebar:: Important + + This page contains only reference information. For tutorials, + please see + + * :ref:`Basic Tutorial ` + * :ref:`Advanced Tutorial ` + * :ref:`Logging Cookbook ` + +.. currentmodule:: logging + +The following useful handlers are provided in the package. Note that three of +the handlers (:class:`StreamHandler`, :class:`FileHandler` and +:class:`NullHandler`) are actually defined in the :mod:`logging` module itself, +but have been documented here along with the other handlers. + +.. _stream-handler: + +StreamHandler +^^^^^^^^^^^^^ + +The :class:`StreamHandler` class, located in the core :mod:`logging` package, +sends logging output to streams such as *sys.stdout*, *sys.stderr* or any +file-like object (or, more precisely, any object which supports :meth:`write` +and :meth:`flush` methods). + + +.. class:: StreamHandler(stream=None) + + Returns a new instance of the :class:`StreamHandler` class. If *stream* is + specified, the instance will use it for logging output; otherwise, *sys.stderr* + will be used. + + + .. method:: emit(record) + + If a formatter is specified, it is used to format the record. The record + is then written to the stream with a newline terminator. If exception + information is present, it is formatted using + :func:`traceback.print_exception` and appended to the stream. + + + .. method:: flush() + + Flushes the stream by calling its :meth:`flush` method. Note that the + :meth:`close` method is inherited from :class:`Handler` and so does + no output, so an explicit :meth:`flush` call may be needed at times. + +.. _file-handler: + +FileHandler +^^^^^^^^^^^ + +The :class:`FileHandler` class, located in the core :mod:`logging` package, +sends logging output to a disk file. It inherits the output functionality from +:class:`StreamHandler`. + + +.. class:: FileHandler(filename, mode='a', encoding=None, delay=False) + + Returns a new instance of the :class:`FileHandler` class. The specified file is + opened and used as the stream for logging. If *mode* is not specified, + :const:`'a'` is used. If *encoding* is not *None*, it is used to open the file + with that encoding. If *delay* is true, then file opening is deferred until the + first call to :meth:`emit`. By default, the file grows indefinitely. + + .. versionchanged:: 2.6 + *delay* was added. + + .. method:: close() + + Closes the file. + + + .. method:: emit(record) + + Outputs the record to the file. + + +.. _null-handler: + +NullHandler +^^^^^^^^^^^ + +.. versionadded:: 2.7 + +The :class:`NullHandler` class, located in the core :mod:`logging` package, +does not do any formatting or output. It is essentially a 'no-op' handler +for use by library developers. + +.. class:: NullHandler() + + Returns a new instance of the :class:`NullHandler` class. + + .. method:: emit(record) + + This method does nothing. + + .. method:: handle(record) + + This method does nothing. + + .. method:: createLock() + + This method returns ``None`` for the lock, since there is no + underlying I/O to which access needs to be serialized. + + +See :ref:`library-config` for more information on how to use +:class:`NullHandler`. + +.. _watched-file-handler: + +WatchedFileHandler +^^^^^^^^^^^^^^^^^^ + +.. currentmodule:: logging.handlers + +.. versionadded:: 2.6 + +The :class:`WatchedFileHandler` class, located in the :mod:`logging.handlers` +module, is a :class:`FileHandler` which watches the file it is logging to. If +the file changes, it is closed and reopened using the file name. + +A file change can happen because of usage of programs such as *newsyslog* and +*logrotate* which perform log file rotation. This handler, intended for use +under Unix/Linux, watches the file to see if it has changed since the last emit. +(A file is deemed to have changed if its device or inode have changed.) If the +file has changed, the old file stream is closed, and the file opened to get a +new stream. + +This handler is not appropriate for use under Windows, because under Windows +open log files cannot be moved or renamed - logging opens the files with +exclusive locks - and so there is no need for such a handler. Furthermore, +*ST_INO* is not supported under Windows; :func:`stat` always returns zero for +this value. + + +.. class:: WatchedFileHandler(filename[,mode[, encoding[, delay]]]) + + Returns a new instance of the :class:`WatchedFileHandler` class. The specified + file is opened and used as the stream for logging. If *mode* is not specified, + :const:`'a'` is used. If *encoding* is not *None*, it is used to open the file + with that encoding. If *delay* is true, then file opening is deferred until the + first call to :meth:`emit`. By default, the file grows indefinitely. + + + .. method:: emit(record) + + Outputs the record to the file, but first checks to see if the file has + changed. If it has, the existing stream is flushed and closed and the + file opened again, before outputting the record to the file. + +.. _rotating-file-handler: + +RotatingFileHandler +^^^^^^^^^^^^^^^^^^^ + +The :class:`RotatingFileHandler` class, located in the :mod:`logging.handlers` +module, supports rotation of disk log files. + + +.. class:: RotatingFileHandler(filename, mode='a', maxBytes=0, backupCount=0, encoding=None, delay=0) + + Returns a new instance of the :class:`RotatingFileHandler` class. The specified + file is opened and used as the stream for logging. If *mode* is not specified, + ``'a'`` is used. If *encoding* is not *None*, it is used to open the file + with that encoding. If *delay* is true, then file opening is deferred until the + first call to :meth:`emit`. By default, the file grows indefinitely. + + You can use the *maxBytes* and *backupCount* values to allow the file to + :dfn:`rollover` at a predetermined size. When the size is about to be exceeded, + the file is closed and a new file is silently opened for output. Rollover occurs + whenever the current log file is nearly *maxBytes* in length; if *maxBytes* is + zero, rollover never occurs. If *backupCount* is non-zero, the system will save + old log files by appending the extensions '.1', '.2' etc., to the filename. For + example, with a *backupCount* of 5 and a base file name of :file:`app.log`, you + would get :file:`app.log`, :file:`app.log.1`, :file:`app.log.2`, up to + :file:`app.log.5`. The file being written to is always :file:`app.log`. When + this file is filled, it is closed and renamed to :file:`app.log.1`, and if files + :file:`app.log.1`, :file:`app.log.2`, etc. exist, then they are renamed to + :file:`app.log.2`, :file:`app.log.3` etc. respectively. + + .. versionchanged:: 2.6 + *delay* was added. + + + .. method:: doRollover() + + Does a rollover, as described above. + + + .. method:: emit(record) + + Outputs the record to the file, catering for rollover as described + previously. + +.. _timed-rotating-file-handler: + +TimedRotatingFileHandler +^^^^^^^^^^^^^^^^^^^^^^^^ + +The :class:`TimedRotatingFileHandler` class, located in the +:mod:`logging.handlers` module, supports rotation of disk log files at certain +timed intervals. + + +.. class:: TimedRotatingFileHandler(filename, when='h', interval=1, backupCount=0, encoding=None, delay=False, utc=False) + + Returns a new instance of the :class:`TimedRotatingFileHandler` class. The + specified file is opened and used as the stream for logging. On rotating it also + sets the filename suffix. Rotating happens based on the product of *when* and + *interval*. + + You can use the *when* to specify the type of *interval*. The list of possible + values is below. Note that they are not case sensitive. + + +----------------+-----------------------+ + | Value | Type of interval | + +================+=======================+ + | ``'S'`` | Seconds | + +----------------+-----------------------+ + | ``'M'`` | Minutes | + +----------------+-----------------------+ + | ``'H'`` | Hours | + +----------------+-----------------------+ + | ``'D'`` | Days | + +----------------+-----------------------+ + | ``'W'`` | Week day (0=Monday) | + +----------------+-----------------------+ + | ``'midnight'`` | Roll over at midnight | + +----------------+-----------------------+ + + The system will save old log files by appending extensions to the filename. + The extensions are date-and-time based, using the strftime format + ``%Y-%m-%d_%H-%M-%S`` or a leading portion thereof, depending on the + rollover interval. + + When computing the next rollover time for the first time (when the handler + is created), the last modification time of an existing log file, or else + the current time, is used to compute when the next rotation will occur. + + If the *utc* argument is true, times in UTC will be used; otherwise + local time is used. + + If *backupCount* is nonzero, at most *backupCount* files + will be kept, and if more would be created when rollover occurs, the oldest + one is deleted. The deletion logic uses the interval to determine which + files to delete, so changing the interval may leave old files lying around. + + If *delay* is true, then file opening is deferred until the first call to + :meth:`emit`. + + .. versionchanged:: 2.6 + *delay* was added. + + .. versionchanged:: 2.7 + *utc* was added. + + + .. method:: doRollover() + + Does a rollover, as described above. + + + .. method:: emit(record) + + Outputs the record to the file, catering for rollover as described above. + + +.. _socket-handler: + +SocketHandler +^^^^^^^^^^^^^ + +The :class:`SocketHandler` class, located in the :mod:`logging.handlers` module, +sends logging output to a network socket. The base class uses a TCP socket. + + +.. class:: SocketHandler(host, port) + + Returns a new instance of the :class:`SocketHandler` class intended to + communicate with a remote machine whose address is given by *host* and *port*. + + + .. method:: close() + + Closes the socket. + + + .. method:: emit() + + Pickles the record's attribute dictionary and writes it to the socket in + binary format. If there is an error with the socket, silently drops the + packet. If the connection was previously lost, re-establishes the + connection. To unpickle the record at the receiving end into a + :class:`LogRecord`, use the :func:`makeLogRecord` function. + + + .. method:: handleError() + + Handles an error which has occurred during :meth:`emit`. The most likely + cause is a lost connection. Closes the socket so that we can retry on the + next event. + + + .. method:: makeSocket() + + This is a factory method which allows subclasses to define the precise + type of socket they want. The default implementation creates a TCP socket + (:const:`socket.SOCK_STREAM`). + + + .. method:: makePickle(record) + + Pickles the record's attribute dictionary in binary format with a length + prefix, and returns it ready for transmission across the socket. + + Note that pickles aren't completely secure. If you are concerned about + security, you may want to override this method to implement a more secure + mechanism. For example, you can sign pickles using HMAC and then verify + them on the receiving end, or alternatively you can disable unpickling of + global objects on the receiving end. + + + .. method:: send(packet) + + Send a pickled string *packet* to the socket. This function allows for + partial sends which can happen when the network is busy. + + + .. method:: createSocket() + + Tries to create a socket; on failure, uses an exponential back-off + algorithm. On intial failure, the handler will drop the message it was + trying to send. When subsequent messages are handled by the same + instance, it will not try connecting until some time has passed. The + default parameters are such that the initial delay is one second, and if + after that delay the connection still can't be made, the handler will + double the delay each time up to a maximum of 30 seconds. + + This behaviour is controlled by the following handler attributes: + + * ``retryStart`` (initial delay, defaulting to 1.0 seconds). + * ``retryFactor`` (multiplier, defaulting to 2.0). + * ``retryMax`` (maximum delay, defaulting to 30.0 seconds). + + This means that if the remote listener starts up *after* the handler has + been used, you could lose messages (since the handler won't even attempt + a connection until the delay has elapsed, but just silently drop messages + during the delay period). + + +.. _datagram-handler: + +DatagramHandler +^^^^^^^^^^^^^^^ + +The :class:`DatagramHandler` class, located in the :mod:`logging.handlers` +module, inherits from :class:`SocketHandler` to support sending logging messages +over UDP sockets. + + +.. class:: DatagramHandler(host, port) + + Returns a new instance of the :class:`DatagramHandler` class intended to + communicate with a remote machine whose address is given by *host* and *port*. + + + .. method:: emit() + + Pickles the record's attribute dictionary and writes it to the socket in + binary format. If there is an error with the socket, silently drops the + packet. To unpickle the record at the receiving end into a + :class:`LogRecord`, use the :func:`makeLogRecord` function. + + + .. method:: makeSocket() + + The factory method of :class:`SocketHandler` is here overridden to create + a UDP socket (:const:`socket.SOCK_DGRAM`). + + + .. method:: send(s) + + Send a pickled string to a socket. + + +.. _syslog-handler: + +SysLogHandler +^^^^^^^^^^^^^ + +The :class:`SysLogHandler` class, located in the :mod:`logging.handlers` module, +supports sending logging messages to a remote or local Unix syslog. + + +.. class:: SysLogHandler(address=('localhost', SYSLOG_UDP_PORT), facility=LOG_USER, socktype=socket.SOCK_DGRAM) + + Returns a new instance of the :class:`SysLogHandler` class intended to + communicate with a remote Unix machine whose address is given by *address* in + the form of a ``(host, port)`` tuple. If *address* is not specified, + ``('localhost', 514)`` is used. The address is used to open a socket. An + alternative to providing a ``(host, port)`` tuple is providing an address as a + string, for example '/dev/log'. In this case, a Unix domain socket is used to + send the message to the syslog. If *facility* is not specified, + :const:`LOG_USER` is used. The type of socket opened depends on the + *socktype* argument, which defaults to :const:`socket.SOCK_DGRAM` and thus + opens a UDP socket. To open a TCP socket (for use with the newer syslog + daemons such as rsyslog), specify a value of :const:`socket.SOCK_STREAM`. + + Note that if your server is not listening on UDP port 514, + :class:`SysLogHandler` may appear not to work. In that case, check what + address you should be using for a domain socket - it's system dependent. + For example, on Linux it's usually '/dev/log' but on OS/X it's + '/var/run/syslog'. You'll need to check your platform and use the + appropriate address (you may need to do this check at runtime if your + application needs to run on several platforms). On Windows, you pretty + much have to use the UDP option. + + .. versionchanged:: 2.7 + *socktype* was added. + + + .. method:: close() + + Closes the socket to the remote host. + + + .. method:: emit(record) + + The record is formatted, and then sent to the syslog server. If exception + information is present, it is *not* sent to the server. + + + .. method:: encodePriority(facility, priority) + + Encodes the facility and priority into an integer. You can pass in strings + or integers - if strings are passed, internal mapping dictionaries are + used to convert them to integers. + + The symbolic ``LOG_`` values are defined in :class:`SysLogHandler` and + mirror the values defined in the ``sys/syslog.h`` header file. + + **Priorities** + + +--------------------------+---------------+ + | Name (string) | Symbolic value| + +==========================+===============+ + | ``alert`` | LOG_ALERT | + +--------------------------+---------------+ + | ``crit`` or ``critical`` | LOG_CRIT | + +--------------------------+---------------+ + | ``debug`` | LOG_DEBUG | + +--------------------------+---------------+ + | ``emerg`` or ``panic`` | LOG_EMERG | + +--------------------------+---------------+ + | ``err`` or ``error`` | LOG_ERR | + +--------------------------+---------------+ + | ``info`` | LOG_INFO | + +--------------------------+---------------+ + | ``notice`` | LOG_NOTICE | + +--------------------------+---------------+ + | ``warn`` or ``warning`` | LOG_WARNING | + +--------------------------+---------------+ + + **Facilities** + + +---------------+---------------+ + | Name (string) | Symbolic value| + +===============+===============+ + | ``auth`` | LOG_AUTH | + +---------------+---------------+ + | ``authpriv`` | LOG_AUTHPRIV | + +---------------+---------------+ + | ``cron`` | LOG_CRON | + +---------------+---------------+ + | ``daemon`` | LOG_DAEMON | + +---------------+---------------+ + | ``ftp`` | LOG_FTP | + +---------------+---------------+ + | ``kern`` | LOG_KERN | + +---------------+---------------+ + | ``lpr`` | LOG_LPR | + +---------------+---------------+ + | ``mail`` | LOG_MAIL | + +---------------+---------------+ + | ``news`` | LOG_NEWS | + +---------------+---------------+ + | ``syslog`` | LOG_SYSLOG | + +---------------+---------------+ + | ``user`` | LOG_USER | + +---------------+---------------+ + | ``uucp`` | LOG_UUCP | + +---------------+---------------+ + | ``local0`` | LOG_LOCAL0 | + +---------------+---------------+ + | ``local1`` | LOG_LOCAL1 | + +---------------+---------------+ + | ``local2`` | LOG_LOCAL2 | + +---------------+---------------+ + | ``local3`` | LOG_LOCAL3 | + +---------------+---------------+ + | ``local4`` | LOG_LOCAL4 | + +---------------+---------------+ + | ``local5`` | LOG_LOCAL5 | + +---------------+---------------+ + | ``local6`` | LOG_LOCAL6 | + +---------------+---------------+ + | ``local7`` | LOG_LOCAL7 | + +---------------+---------------+ + + .. method:: mapPriority(levelname) + + Maps a logging level name to a syslog priority name. + You may need to override this if you are using custom levels, or + if the default algorithm is not suitable for your needs. The + default algorithm maps ``DEBUG``, ``INFO``, ``WARNING``, ``ERROR`` and + ``CRITICAL`` to the equivalent syslog names, and all other level + names to 'warning'. + +.. _nt-eventlog-handler: + +NTEventLogHandler +^^^^^^^^^^^^^^^^^ + +The :class:`NTEventLogHandler` class, located in the :mod:`logging.handlers` +module, supports sending logging messages to a local Windows NT, Windows 2000 or +Windows XP event log. Before you can use it, you need Mark Hammond's Win32 +extensions for Python installed. + + +.. class:: NTEventLogHandler(appname, dllname=None, logtype='Application') + + Returns a new instance of the :class:`NTEventLogHandler` class. The *appname* is + used to define the application name as it appears in the event log. An + appropriate registry entry is created using this name. The *dllname* should give + the fully qualified pathname of a .dll or .exe which contains message + definitions to hold in the log (if not specified, ``'win32service.pyd'`` is used + - this is installed with the Win32 extensions and contains some basic + placeholder message definitions. Note that use of these placeholders will make + your event logs big, as the entire message source is held in the log. If you + want slimmer logs, you have to pass in the name of your own .dll or .exe which + contains the message definitions you want to use in the event log). The + *logtype* is one of ``'Application'``, ``'System'`` or ``'Security'``, and + defaults to ``'Application'``. + + + .. method:: close() + + At this point, you can remove the application name from the registry as a + source of event log entries. However, if you do this, you will not be able + to see the events as you intended in the Event Log Viewer - it needs to be + able to access the registry to get the .dll name. The current version does + not do this. + + + .. method:: emit(record) + + Determines the message ID, event category and event type, and then logs + the message in the NT event log. + + + .. method:: getEventCategory(record) + + Returns the event category for the record. Override this if you want to + specify your own categories. This version returns 0. + + + .. method:: getEventType(record) + + Returns the event type for the record. Override this if you want to + specify your own types. This version does a mapping using the handler's + typemap attribute, which is set up in :meth:`__init__` to a dictionary + which contains mappings for :const:`DEBUG`, :const:`INFO`, + :const:`WARNING`, :const:`ERROR` and :const:`CRITICAL`. If you are using + your own levels, you will either need to override this method or place a + suitable dictionary in the handler's *typemap* attribute. + + + .. method:: getMessageID(record) + + Returns the message ID for the record. If you are using your own messages, + you could do this by having the *msg* passed to the logger being an ID + rather than a format string. Then, in here, you could use a dictionary + lookup to get the message ID. This version returns 1, which is the base + message ID in :file:`win32service.pyd`. + +.. _smtp-handler: + +SMTPHandler +^^^^^^^^^^^ + +The :class:`SMTPHandler` class, located in the :mod:`logging.handlers` module, +supports sending logging messages to an email address via SMTP. + + +.. class:: SMTPHandler(mailhost, fromaddr, toaddrs, subject, credentials=None, secure=None) + + Returns a new instance of the :class:`SMTPHandler` class. The instance is + initialized with the from and to addresses and subject line of the email. + The *toaddrs* should be a list of strings. To specify a non-standard SMTP + port, use the (host, port) tuple format for the *mailhost* argument. If you + use a string, the standard SMTP port is used. If your SMTP server requires + authentication, you can specify a (username, password) tuple for the + *credentials* argument. If *secure* is True, then the handler will attempt + to use TLS for the email transmission. + + .. versionchanged:: 2.6 + *credentials* was added. + + .. versionchanged:: 2.7 + *secure* was added. + + + .. method:: emit(record) + + Formats the record and sends it to the specified addressees. + + + .. method:: getSubject(record) + + If you want to specify a subject line which is record-dependent, override + this method. + +.. _memory-handler: + +MemoryHandler +^^^^^^^^^^^^^ + +The :class:`MemoryHandler` class, located in the :mod:`logging.handlers` module, +supports buffering of logging records in memory, periodically flushing them to a +:dfn:`target` handler. Flushing occurs whenever the buffer is full, or when an +event of a certain severity or greater is seen. + +:class:`MemoryHandler` is a subclass of the more general +:class:`BufferingHandler`, which is an abstract class. This buffers logging +records in memory. Whenever each record is added to the buffer, a check is made +by calling :meth:`shouldFlush` to see if the buffer should be flushed. If it +should, then :meth:`flush` is expected to do the needful. + + +.. class:: BufferingHandler(capacity) + + Initializes the handler with a buffer of the specified capacity. + + + .. method:: emit(record) + + Appends the record to the buffer. If :meth:`shouldFlush` returns true, + calls :meth:`flush` to process the buffer. + + + .. method:: flush() + + You can override this to implement custom flushing behavior. This version + just zaps the buffer to empty. + + + .. method:: shouldFlush(record) + + Returns true if the buffer is up to capacity. This method can be + overridden to implement custom flushing strategies. + + +.. class:: MemoryHandler(capacity, flushLevel=ERROR, target=None) + + Returns a new instance of the :class:`MemoryHandler` class. The instance is + initialized with a buffer size of *capacity*. If *flushLevel* is not specified, + :const:`ERROR` is used. If no *target* is specified, the target will need to be + set using :meth:`setTarget` before this handler does anything useful. + + + .. method:: close() + + Calls :meth:`flush`, sets the target to :const:`None` and clears the + buffer. + + + .. method:: flush() + + For a :class:`MemoryHandler`, flushing means just sending the buffered + records to the target, if there is one. The buffer is also cleared when + this happens. Override if you want different behavior. + + + .. method:: setTarget(target) + .. versionchanged:: 2.6 + *credentials* was added. + + + Sets the target handler for this handler. + + + .. method:: shouldFlush(record) + + Checks for buffer full or a record at the *flushLevel* or higher. + + +.. _http-handler: + +HTTPHandler +^^^^^^^^^^^ + +The :class:`HTTPHandler` class, located in the :mod:`logging.handlers` module, +supports sending logging messages to a Web server, using either ``GET`` or +``POST`` semantics. + + +.. class:: HTTPHandler(host, url, method='GET') + + Returns a new instance of the :class:`HTTPHandler` class. The *host* can be + of the form ``host:port``, should you need to use a specific port number. + If no *method* is specified, ``GET`` is used. + + + .. method:: emit(record) + + Sends the record to the Web server as a percent-encoded dictionary. + + +.. seealso:: + + Module :mod:`logging` + API reference for the logging module. + + Module :mod:`logging.config` + Configuration API for the logging module. + + diff --git a/Doc/library/logging.rst b/Doc/library/logging.rst --- a/Doc/library/logging.rst +++ b/Doc/library/logging.rst @@ -2,7 +2,7 @@ ============================================== .. module:: logging - :synopsis: Flexible error logging system for applications. + :synopsis: Flexible event logging system for applications. .. moduleauthor:: Vinay Sajip @@ -11,690 +11,645 @@ .. index:: pair: Errors; logging +.. sidebar:: Important + + This page contains the API reference information. For tutorial + information and discussion of more advanced topics, see + + * :ref:`Basic Tutorial ` + * :ref:`Advanced Tutorial ` + * :ref:`Logging Cookbook ` + + .. versionadded:: 2.3 -This module defines functions and classes which implement a flexible error -logging system for applications. - -Logging is performed by calling methods on instances of the :class:`Logger` -class (hereafter called :dfn:`loggers`). Each instance has a name, and they are -conceptually arranged in a namespace hierarchy using dots (periods) as -separators. For example, a logger named "scan" is the parent of loggers -"scan.text", "scan.html" and "scan.pdf". Logger names can be anything you want, -and indicate the area of an application in which a logged message originates. - -Logged messages also have levels of importance associated with them. The default -levels provided are :const:`DEBUG`, :const:`INFO`, :const:`WARNING`, -:const:`ERROR` and :const:`CRITICAL`. As a convenience, you indicate the -importance of a logged message by calling an appropriate method of -:class:`Logger`. The methods are :meth:`debug`, :meth:`info`, :meth:`warning`, -:meth:`error` and :meth:`critical`, which mirror the default levels. You are not -constrained to use these levels: you can specify your own and use a more general -:class:`Logger` method, :meth:`log`, which takes an explicit level argument. - - -Logging tutorial ----------------- +This module defines functions and classes which implement a flexible event +logging system for applications and libraries. The key benefit of having the logging API provided by a standard library module is that all Python modules can participate in logging, so your application log -can include messages from third-party modules. +can include your own messages integrated with messages from third-party +modules. -It is, of course, possible to log messages with different verbosity levels or to -different destinations. Support for writing log messages to files, HTTP -GET/POST locations, email via SMTP, generic sockets, or OS-specific logging -mechanisms are all supported by the standard module. You can also create your -own log destination class if you have special requirements not met by any of the -built-in classes. +The module provides a lot of functionality and flexibility. If you are +unfamiliar with logging, the best way to get to grips with it is to see the +tutorials (see the links on the right). -Simple examples -^^^^^^^^^^^^^^^ +The basic classes defined by the module, together with their functions, are +listed below. -.. sectionauthor:: Doug Hellmann -.. (see ) +* Loggers expose the interface that application code directly uses. +* Handlers send the log records (created by loggers) to the appropriate + destination. +* Filters provide a finer grained facility for determining which log records + to output. +* Formatters specify the layout of log records in the final output. -Most applications are probably going to want to log to a file, so let's start -with that case. Using the :func:`basicConfig` function, we can set up the -default handler so that debug messages are written to a file (in the example, -we assume that you have the appropriate permissions to create a file called -*example.log* in the current directory):: - import logging - LOG_FILENAME = 'example.log' - logging.basicConfig(filename=LOG_FILENAME,level=logging.DEBUG) +.. _logger: - logging.debug('This message should go to the log file') +Logger Objects +-------------- -And now if we open the file and look at what we have, we should find the log -message:: +Loggers have the following attributes and methods. Note that Loggers are never +instantiated directly, but always through the module-level function +``logging.getLogger(name)``. - DEBUG:root:This message should go to the log file +.. class:: Logger -If you run the script repeatedly, the additional log messages are appended to -the file. To create a new file each time, you can pass a *filemode* argument to -:func:`basicConfig` with a value of ``'w'``. Rather than managing the file size -yourself, though, it is simpler to use a :class:`RotatingFileHandler`:: +.. attribute:: Logger.propagate - import glob - import logging - import logging.handlers + If this evaluates to false, logging messages are not passed by this logger or by + its child loggers to the handlers of higher level (ancestor) loggers. The + constructor sets this attribute to 1. - LOG_FILENAME = 'logging_rotatingfile_example.out' - # Set up a specific logger with our desired output level - my_logger = logging.getLogger('MyLogger') - my_logger.setLevel(logging.DEBUG) +.. method:: Logger.setLevel(lvl) - # Add the log message handler to the logger - handler = logging.handlers.RotatingFileHandler( - LOG_FILENAME, maxBytes=20, backupCount=5) + Sets the threshold for this logger to *lvl*. Logging messages which are less + severe than *lvl* will be ignored. When a logger is created, the level is set to + :const:`NOTSET` (which causes all messages to be processed when the logger is + the root logger, or delegation to the parent when the logger is a non-root + logger). Note that the root logger is created with level :const:`WARNING`. - my_logger.addHandler(handler) + The term 'delegation to the parent' means that if a logger has a level of + NOTSET, its chain of ancestor loggers is traversed until either an ancestor with + a level other than NOTSET is found, or the root is reached. - # Log some messages - for i in range(20): - my_logger.debug('i = %d' % i) + If an ancestor is found with a level other than NOTSET, then that ancestor's + level is treated as the effective level of the logger where the ancestor search + began, and is used to determine how a logging event is handled. - # See what files are created - logfiles = glob.glob('%s*' % LOG_FILENAME) + If the root is reached, and it has a level of NOTSET, then all messages will be + processed. Otherwise, the root's level will be used as the effective level. - for filename in logfiles: - print filename -The result should be 6 separate files, each with part of the log history for the -application:: +.. method:: Logger.isEnabledFor(lvl) - logging_rotatingfile_example.out - logging_rotatingfile_example.out.1 - logging_rotatingfile_example.out.2 - logging_rotatingfile_example.out.3 - logging_rotatingfile_example.out.4 - logging_rotatingfile_example.out.5 + Indicates if a message of severity *lvl* would be processed by this logger. + This method checks first the module-level level set by + ``logging.disable(lvl)`` and then the logger's effective level as determined + by :meth:`getEffectiveLevel`. -The most current file is always :file:`logging_rotatingfile_example.out`, -and each time it reaches the size limit it is renamed with the suffix -``.1``. Each of the existing backup files is renamed to increment the suffix -(``.1`` becomes ``.2``, etc.) and the ``.6`` file is erased. -Obviously this example sets the log length much much too small as an extreme -example. You would want to set *maxBytes* to an appropriate value. +.. method:: Logger.getEffectiveLevel() -Another useful feature of the logging API is the ability to produce different -messages at different log levels. This allows you to instrument your code with -debug messages, for example, but turning the log level down so that those debug -messages are not written for your production system. The default levels are -``NOTSET``, ``DEBUG``, ``INFO``, ``WARNING``, ``ERROR`` and ``CRITICAL``. + Indicates the effective level for this logger. If a value other than + :const:`NOTSET` has been set using :meth:`setLevel`, it is returned. Otherwise, + the hierarchy is traversed towards the root until a value other than + :const:`NOTSET` is found, and that value is returned. -The logger, handler, and log message call each specify a level. The log message -is only emitted if the handler and logger are configured to emit messages of -that level or lower. For example, if a message is ``CRITICAL``, and the logger -is set to ``ERROR``, the message is emitted. If a message is a ``WARNING``, and -the logger is set to produce only ``ERROR``\s, the message is not emitted:: - import logging - import sys +.. method:: Logger.getChild(suffix) - LEVELS = {'debug': logging.DEBUG, - 'info': logging.INFO, - 'warning': logging.WARNING, - 'error': logging.ERROR, - 'critical': logging.CRITICAL} + Returns a logger which is a descendant to this logger, as determined by the suffix. + Thus, ``logging.getLogger('abc').getChild('def.ghi')`` would return the same + logger as would be returned by ``logging.getLogger('abc.def.ghi')``. This is a + convenience method, useful when the parent logger is named using e.g. ``__name__`` + rather than a literal string. - if len(sys.argv) > 1: - level_name = sys.argv[1] - level = LEVELS.get(level_name, logging.NOTSET) - logging.basicConfig(level=level) + .. versionadded:: 2.7 - logging.debug('This is a debug message') - logging.info('This is an info message') - logging.warning('This is a warning message') - logging.error('This is an error message') - logging.critical('This is a critical error message') -Run the script with an argument like 'debug' or 'warning' to see which messages -show up at different levels:: +.. method:: Logger.debug(msg, *args, **kwargs) - $ python logging_level_example.py debug - DEBUG:root:This is a debug message - INFO:root:This is an info message - WARNING:root:This is a warning message - ERROR:root:This is an error message - CRITICAL:root:This is a critical error message + Logs a message with level :const:`DEBUG` on this logger. The *msg* is the + message format string, and the *args* are the arguments which are merged into + *msg* using the string formatting operator. (Note that this means that you can + use keywords in the format string, together with a single dictionary argument.) - $ python logging_level_example.py info - INFO:root:This is an info message - WARNING:root:This is a warning message - ERROR:root:This is an error message - CRITICAL:root:This is a critical error message + There are two keyword arguments in *kwargs* which are inspected: *exc_info* + which, if it does not evaluate as false, causes exception information to be + added to the logging message. If an exception tuple (in the format returned by + :func:`sys.exc_info`) is provided, it is used; otherwise, :func:`sys.exc_info` + is called to get the exception information. -You will notice that these log messages all have ``root`` embedded in them. The -logging module supports a hierarchy of loggers with different names. An easy -way to tell where a specific log message comes from is to use a separate logger -object for each of your modules. Each new logger "inherits" the configuration -of its parent, and log messages sent to a logger include the name of that -logger. Optionally, each logger can be configured differently, so that messages -from different modules are handled in different ways. Let's look at a simple -example of how to log from different modules so it is easy to trace the source -of the message:: + The second keyword argument is *extra* which can be used to pass a + dictionary which is used to populate the __dict__ of the LogRecord created for + the logging event with user-defined attributes. These custom attributes can then + be used as you like. For example, they could be incorporated into logged + messages. For example:: - import logging + FORMAT = '%(asctime)-15s %(clientip)s %(user)-8s %(message)s' + logging.basicConfig(format=FORMAT) + d = { 'clientip' : '192.168.0.1', 'user' : 'fbloggs' } + logger = logging.getLogger('tcpserver') + logger.warning('Protocol problem: %s', 'connection reset', extra=d) - logging.basicConfig(level=logging.WARNING) + would print something like :: - logger1 = logging.getLogger('package1.module1') - logger2 = logging.getLogger('package2.module2') + 2006-02-08 22:20:02,165 192.168.0.1 fbloggs Protocol problem: connection reset - logger1.warning('This message comes from one module') - logger2.warning('And this message comes from another module') + The keys in the dictionary passed in *extra* should not clash with the keys used + by the logging system. (See the :class:`Formatter` documentation for more + information on which keys are used by the logging system.) -And the output:: + If you choose to use these attributes in logged messages, you need to exercise + some care. In the above example, for instance, the :class:`Formatter` has been + set up with a format string which expects 'clientip' and 'user' in the attribute + dictionary of the LogRecord. If these are missing, the message will not be + logged because a string formatting exception will occur. So in this case, you + always need to pass the *extra* dictionary with these keys. - $ python logging_modules_example.py - WARNING:package1.module1:This message comes from one module - WARNING:package2.module2:And this message comes from another module + While this might be annoying, this feature is intended for use in specialized + circumstances, such as multi-threaded servers where the same code executes in + many contexts, and interesting conditions which arise are dependent on this + context (such as remote client IP address and authenticated user name, in the + above example). In such circumstances, it is likely that specialized + :class:`Formatter`\ s would be used with particular :class:`Handler`\ s. -There are many more options for configuring logging, including different log -message formatting options, having messages delivered to multiple destinations, -and changing the configuration of a long-running application on the fly using a -socket interface. All of these options are covered in depth in the library -module documentation. -Loggers -^^^^^^^ +.. method:: Logger.info(msg, *args, **kwargs) -The logging library takes a modular approach and offers the several categories -of components: loggers, handlers, filters, and formatters. Loggers expose the -interface that application code directly uses. Handlers send the log records to -the appropriate destination. Filters provide a finer grained facility for -determining which log records to send on to a handler. Formatters specify the -layout of the resultant log record. + Logs a message with level :const:`INFO` on this logger. The arguments are + interpreted as for :meth:`debug`. -:class:`Logger` objects have a threefold job. First, they expose several -methods to application code so that applications can log messages at runtime. -Second, logger objects determine which log messages to act upon based upon -severity (the default filtering facility) or filter objects. Third, logger -objects pass along relevant log messages to all interested log handlers. -The most widely used methods on logger objects fall into two categories: -configuration and message sending. +.. method:: Logger.warning(msg, *args, **kwargs) -* :meth:`Logger.setLevel` specifies the lowest-severity log message a logger - will handle, where debug is the lowest built-in severity level and critical is - the highest built-in severity. For example, if the severity level is info, - the logger will handle only info, warning, error, and critical messages and - will ignore debug messages. + Logs a message with level :const:`WARNING` on this logger. The arguments are + interpreted as for :meth:`debug`. -* :meth:`Logger.addFilter` and :meth:`Logger.removeFilter` add and remove filter - objects from the logger object. This tutorial does not address filters. -With the logger object configured, the following methods create log messages: +.. method:: Logger.error(msg, *args, **kwargs) -* :meth:`Logger.debug`, :meth:`Logger.info`, :meth:`Logger.warning`, - :meth:`Logger.error`, and :meth:`Logger.critical` all create log records with - a message and a level that corresponds to their respective method names. The - message is actually a format string, which may contain the standard string - substitution syntax of :const:`%s`, :const:`%d`, :const:`%f`, and so on. The - rest of their arguments is a list of objects that correspond with the - substitution fields in the message. With regard to :const:`**kwargs`, the - logging methods care only about a keyword of :const:`exc_info` and use it to - determine whether to log exception information. + Logs a message with level :const:`ERROR` on this logger. The arguments are + interpreted as for :meth:`debug`. -* :meth:`Logger.exception` creates a log message similar to - :meth:`Logger.error`. The difference is that :meth:`Logger.exception` dumps a - stack trace along with it. Call this method only from an exception handler. -* :meth:`Logger.log` takes a log level as an explicit argument. This is a - little more verbose for logging messages than using the log level convenience - methods listed above, but this is how to log at custom log levels. +.. method:: Logger.critical(msg, *args, **kwargs) -:func:`getLogger` returns a reference to a logger instance with the specified -name if it is provided, or ``root`` if not. The names are period-separated -hierarchical structures. Multiple calls to :func:`getLogger` with the same name -will return a reference to the same logger object. Loggers that are further -down in the hierarchical list are children of loggers higher up in the list. -For example, given a logger with a name of ``foo``, loggers with names of -``foo.bar``, ``foo.bar.baz``, and ``foo.bam`` are all descendants of ``foo``. -Child loggers propagate messages up to the handlers associated with their -ancestor loggers. Because of this, it is unnecessary to define and configure -handlers for all the loggers an application uses. It is sufficient to -configure handlers for a top-level logger and create child loggers as needed. + Logs a message with level :const:`CRITICAL` on this logger. The arguments are + interpreted as for :meth:`debug`. -Handlers -^^^^^^^^ +.. method:: Logger.log(lvl, msg, *args, **kwargs) -:class:`Handler` objects are responsible for dispatching the appropriate log -messages (based on the log messages' severity) to the handler's specified -destination. Logger objects can add zero or more handler objects to themselves -with an :func:`addHandler` method. As an example scenario, an application may -want to send all log messages to a log file, all log messages of error or higher -to stdout, and all messages of critical to an email address. This scenario -requires three individual handlers where each handler is responsible for sending -messages of a specific severity to a specific location. + Logs a message with integer level *lvl* on this logger. The other arguments are + interpreted as for :meth:`debug`. -The standard library includes quite a few handler types; this tutorial uses only -:class:`StreamHandler` and :class:`FileHandler` in its examples. -There are very few methods in a handler for application developers to concern -themselves with. The only handler methods that seem relevant for application -developers who are using the built-in handler objects (that is, not creating -custom handlers) are the following configuration methods: +.. method:: Logger.exception(msg, *args) -* The :meth:`Handler.setLevel` method, just as in logger objects, specifies the - lowest severity that will be dispatched to the appropriate destination. Why - are there two :func:`setLevel` methods? The level set in the logger - determines which severity of messages it will pass to its handlers. The level - set in each handler determines which messages that handler will send on. + Logs a message with level :const:`ERROR` on this logger. The arguments are + interpreted as for :meth:`debug`. Exception info is added to the logging + message. This method should only be called from an exception handler. -* :func:`setFormatter` selects a Formatter object for this handler to use. -* :func:`addFilter` and :func:`removeFilter` respectively configure and - deconfigure filter objects on handlers. +.. method:: Logger.addFilter(filt) -Application code should not directly instantiate and use instances of -:class:`Handler`. Instead, the :class:`Handler` class is a base class that -defines the interface that all handlers should have and establishes some -default behavior that child classes can use (or override). + Adds the specified filter *filt* to this logger. -Formatters -^^^^^^^^^^ +.. method:: Logger.removeFilter(filt) -Formatter objects configure the final order, structure, and contents of the log -message. Unlike the base :class:`logging.Handler` class, application code may -instantiate formatter classes, although you could likely subclass the formatter -if your application needs special behavior. The constructor takes two optional -arguments: a message format string and a date format string. If there is no -message format string, the default is to use the raw message. If there is no -date format string, the default date format is:: + Removes the specified filter *filt* from this logger. - %Y-%m-%d %H:%M:%S -with the milliseconds tacked on at the end. +.. method:: Logger.filter(record) -The message format string uses ``%()s`` styled string -substitution; the possible keys are documented in :ref:`formatter`. + Applies this logger's filters to the record and returns a true value if the + record is to be processed. -The following message format string will log the time in a human-readable -format, the severity of the message, and the contents of the message, in that -order:: - "%(asctime)s - %(levelname)s - %(message)s" +.. method:: Logger.addHandler(hdlr) -Formatters use a user-configurable function to convert the creation time of a -record to a tuple. By default, :func:`time.localtime` is used; to change this -for a particular formatter instance, set the ``converter`` attribute of the -instance to a function with the same signature as :func:`time.localtime` or -:func:`time.gmtime`. To change it for all formatters, for example if you want -all logging times to be shown in GMT, set the ``converter`` attribute in the -Formatter class (to ``time.gmtime`` for GMT display). + Adds the specified handler *hdlr* to this logger. -Configuring Logging -^^^^^^^^^^^^^^^^^^^ +.. method:: Logger.removeHandler(hdlr) -Programmers can configure logging in three ways: + Removes the specified handler *hdlr* from this logger. -1. Creating loggers, handlers, and formatters explicitly using Python - code that calls the configuration methods listed above. -2. Creating a logging config file and reading it using the :func:`fileConfig` - function. -3. Creating a dictionary of configuration information and passing it - to the :func:`dictConfig` function. -The following example configures a very simple logger, a console -handler, and a simple formatter using Python code:: +.. method:: Logger.findCaller() - import logging + Finds the caller's source filename and line number. Returns the filename, line + number and function name as a 3-element tuple. - # create logger - logger = logging.getLogger("simple_example") - logger.setLevel(logging.DEBUG) + .. versionchanged:: 2.4 + The function name was added. In earlier versions, the filename and line + number were returned as a 2-element tuple. - # create console handler and set level to debug - ch = logging.StreamHandler() - ch.setLevel(logging.DEBUG) +.. method:: Logger.handle(record) - # create formatter - formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s") + Handles a record by passing it to all handlers associated with this logger and + its ancestors (until a false value of *propagate* is found). This method is used + for unpickled records received from a socket, as well as those created locally. + Logger-level filtering is applied using :meth:`~Logger.filter`. - # add formatter to ch - ch.setFormatter(formatter) - # add ch to logger - logger.addHandler(ch) +.. method:: Logger.makeRecord(name, lvl, fn, lno, msg, args, exc_info, func=None, extra=None) - # "application" code - logger.debug("debug message") - logger.info("info message") - logger.warn("warn message") - logger.error("error message") - logger.critical("critical message") + This is a factory method which can be overridden in subclasses to create + specialized :class:`LogRecord` instances. -Running this module from the command line produces the following output:: + .. versionchanged:: 2.5 + *func* and *extra* were added. - $ python simple_logging_module.py - 2005-03-19 15:10:26,618 - simple_example - DEBUG - debug message - 2005-03-19 15:10:26,620 - simple_example - INFO - info message - 2005-03-19 15:10:26,695 - simple_example - WARNING - warn message - 2005-03-19 15:10:26,697 - simple_example - ERROR - error message - 2005-03-19 15:10:26,773 - simple_example - CRITICAL - critical message +.. _handler: -The following Python module creates a logger, handler, and formatter nearly -identical to those in the example listed above, with the only difference being -the names of the objects:: +Handler Objects +--------------- - import logging - import logging.config +Handlers have the following attributes and methods. Note that :class:`Handler` +is never instantiated directly; this class acts as a base for more useful +subclasses. However, the :meth:`__init__` method in subclasses needs to call +:meth:`Handler.__init__`. - logging.config.fileConfig("logging.conf") - # create logger - logger = logging.getLogger("simpleExample") +.. method:: Handler.__init__(level=NOTSET) - # "application" code - logger.debug("debug message") - logger.info("info message") - logger.warn("warn message") - logger.error("error message") - logger.critical("critical message") + Initializes the :class:`Handler` instance by setting its level, setting the list + of filters to the empty list and creating a lock (using :meth:`createLock`) for + serializing access to an I/O mechanism. -Here is the logging.conf file:: - [loggers] - keys=root,simpleExample +.. method:: Handler.createLock() - [handlers] - keys=consoleHandler + Initializes a thread lock which can be used to serialize access to underlying + I/O functionality which may not be threadsafe. - [formatters] - keys=simpleFormatter - [logger_root] - level=DEBUG - handlers=consoleHandler +.. method:: Handler.acquire() - [logger_simpleExample] - level=DEBUG - handlers=consoleHandler - qualname=simpleExample - propagate=0 + Acquires the thread lock created with :meth:`createLock`. - [handler_consoleHandler] - class=StreamHandler - level=DEBUG - formatter=simpleFormatter - args=(sys.stdout,) - [formatter_simpleFormatter] - format=%(asctime)s - %(name)s - %(levelname)s - %(message)s - datefmt= +.. method:: Handler.release() -The output is nearly identical to that of the non-config-file-based example:: + Releases the thread lock acquired with :meth:`acquire`. - $ python simple_logging_config.py - 2005-03-19 15:38:55,977 - simpleExample - DEBUG - debug message - 2005-03-19 15:38:55,979 - simpleExample - INFO - info message - 2005-03-19 15:38:56,054 - simpleExample - WARNING - warn message - 2005-03-19 15:38:56,055 - simpleExample - ERROR - error message - 2005-03-19 15:38:56,130 - simpleExample - CRITICAL - critical message -You can see that the config file approach has a few advantages over the Python -code approach, mainly separation of configuration and code and the ability of -noncoders to easily modify the logging properties. +.. method:: Handler.setLevel(lvl) -Note that the class names referenced in config files need to be either relative -to the logging module, or absolute values which can be resolved using normal -import mechanisms. Thus, you could use either :class:`handlers.WatchedFileHandler` -(relative to the logging module) or :class:`mypackage.mymodule.MyHandler` (for a -class defined in package :mod:`mypackage` and module :mod:`mymodule`, where -:mod:`mypackage` is available on the Python import path). + Sets the threshold for this handler to *lvl*. Logging messages which are less + severe than *lvl* will be ignored. When a handler is created, the level is set + to :const:`NOTSET` (which causes all messages to be processed). + + +.. method:: Handler.setFormatter(form) + + Sets the :class:`Formatter` for this handler to *form*. + + +.. method:: Handler.addFilter(filt) + + Adds the specified filter *filt* to this handler. + + +.. method:: Handler.removeFilter(filt) + + Removes the specified filter *filt* from this handler. + + +.. method:: Handler.filter(record) + + Applies this handler's filters to the record and returns a true value if the + record is to be processed. + + +.. method:: Handler.flush() + + Ensure all logging output has been flushed. This version does nothing and is + intended to be implemented by subclasses. + + +.. method:: Handler.close() + + Tidy up any resources used by the handler. This version does no output but + removes the handler from an internal list of handlers which is closed when + :func:`shutdown` is called. Subclasses should ensure that this gets called + from overridden :meth:`close` methods. + + +.. method:: Handler.handle(record) + + Conditionally emits the specified logging record, depending on filters which may + have been added to the handler. Wraps the actual emission of the record with + acquisition/release of the I/O thread lock. + + +.. method:: Handler.handleError(record) + + This method should be called from handlers when an exception is encountered + during an :meth:`emit` call. By default it does nothing, which means that + exceptions get silently ignored. This is what is mostly wanted for a logging + system - most users will not care about errors in the logging system, they are + more interested in application errors. You could, however, replace this with a + custom handler if you wish. The specified record is the one which was being + processed when the exception occurred. + + +.. method:: Handler.format(record) + + Do formatting for a record - if a formatter is set, use it. Otherwise, use the + default formatter for the module. + + +.. method:: Handler.emit(record) + + Do whatever it takes to actually log the specified logging record. This version + is intended to be implemented by subclasses and so raises a + :exc:`NotImplementedError`. + +For a list of handlers included as standard, see :mod:`logging.handlers`. + +.. _formatter-objects: + +Formatter Objects +----------------- + +.. currentmodule:: logging + +:class:`Formatter` objects have the following attributes and methods. They are +responsible for converting a :class:`LogRecord` to (usually) a string which can +be interpreted by either a human or an external system. The base +:class:`Formatter` allows a formatting string to be specified. If none is +supplied, the default value of ``'%(message)s'`` is used. + +A Formatter can be initialized with a format string which makes use of knowledge +of the :class:`LogRecord` attributes - such as the default value mentioned above +making use of the fact that the user's message and arguments are pre-formatted +into a :class:`LogRecord`'s *message* attribute. This format string contains +standard Python %-style mapping keys. See section :ref:`string-formatting` +for more information on string formatting. + +The useful mapping keys in a :class:`LogRecord` are given in the section on +:ref:`logrecord-attributes`. + + +.. class:: Formatter(fmt=None, datefmt=None) + + Returns a new instance of the :class:`Formatter` class. The instance is + initialized with a format string for the message as a whole, as well as a + format string for the date/time portion of a message. If no *fmt* is + specified, ``'%(message)s'`` is used. If no *datefmt* is specified, the + ISO8601 date format is used. + + .. method:: format(record) + + The record's attribute dictionary is used as the operand to a string + formatting operation. Returns the resulting string. Before formatting the + dictionary, a couple of preparatory steps are carried out. The *message* + attribute of the record is computed using *msg* % *args*. If the + formatting string contains ``'(asctime)'``, :meth:`formatTime` is called + to format the event time. If there is exception information, it is + formatted using :meth:`formatException` and appended to the message. Note + that the formatted exception information is cached in attribute + *exc_text*. This is useful because the exception information can be + pickled and sent across the wire, but you should be careful if you have + more than one :class:`Formatter` subclass which customizes the formatting + of exception information. In this case, you will have to clear the cached + value after a formatter has done its formatting, so that the next + formatter to handle the event doesn't use the cached value but + recalculates it afresh. + + + .. method:: formatTime(record, datefmt=None) + + This method should be called from :meth:`format` by a formatter which + wants to make use of a formatted time. This method can be overridden in + formatters to provide for any specific requirement, but the basic behavior + is as follows: if *datefmt* (a string) is specified, it is used with + :func:`time.strftime` to format the creation time of the + record. Otherwise, the ISO8601 format is used. The resulting string is + returned. + + + .. method:: formatException(exc_info) + + Formats the specified exception information (a standard exception tuple as + returned by :func:`sys.exc_info`) as a string. This default implementation + just uses :func:`traceback.print_exception`. The resulting string is + returned. + +.. _filter: + +Filter Objects +-------------- + +``Filters`` can be used by ``Handlers`` and ``Loggers`` for more sophisticated +filtering than is provided by levels. The base filter class only allows events +which are below a certain point in the logger hierarchy. For example, a filter +initialized with 'A.B' will allow events logged by loggers 'A.B', 'A.B.C', +'A.B.C.D', 'A.B.D' etc. but not 'A.BB', 'B.A.B' etc. If initialized with the +empty string, all events are passed. + + +.. class:: Filter(name='') + + Returns an instance of the :class:`Filter` class. If *name* is specified, it + names a logger which, together with its children, will have its events allowed + through the filter. If *name* is the empty string, allows every event. + + + .. method:: filter(record) + + Is the specified record to be logged? Returns zero for no, nonzero for + yes. If deemed appropriate, the record may be modified in-place by this + method. + +Note that filters attached to handlers are consulted whenever an event is +emitted by the handler, whereas filters attached to loggers are consulted +whenever an event is logged to the handler (using :meth:`debug`, :meth:`info`, +etc.) This means that events which have been generated by descendant loggers +will not be filtered by a logger's filter setting, unless the filter has also +been applied to those descendant loggers. + +You don't actually need to subclass ``Filter``: you can pass any instance +which has a ``filter`` method with the same semantics. + +Although filters are used primarily to filter records based on more +sophisticated criteria than levels, they get to see every record which is +processed by the handler or logger they're attached to: this can be useful if +you want to do things like counting how many records were processed by a +particular logger or handler, or adding, changing or removing attributes in +the LogRecord being processed. Obviously changing the LogRecord needs to be +done with some care, but it does allow the injection of contextual information +into logs (see :ref:`filters-contextual`). + +.. _log-record: + +LogRecord Objects +----------------- + +:class:`LogRecord` instances are created automatically by the :class:`Logger` +every time something is logged, and can be created manually via +:func:`makeLogRecord` (for example, from a pickled event received over the +wire). + + +.. class:: LogRecord(name, level, pathname, lineno, msg, args, exc_info, func=None) + + Contains all the information pertinent to the event being logged. + + The primary information is passed in :attr:`msg` and :attr:`args`, which + are combined using ``msg % args`` to create the :attr:`message` field of the + record. + + :param name: The name of the logger used to log the event represented by + this LogRecord. + :param level: The numeric level of the logging event (one of DEBUG, INFO etc.) + :param pathname: The full pathname of the source file where the logging call + was made. + :param lineno: The line number in the source file where the logging call was + made. + :param msg: The event description message, possibly a format string with + placeholders for variable data. + :param args: Variable data to merge into the *msg* argument to obtain the + event description. + :param exc_info: An exception tuple with the current exception information, + or *None* if no exception information is available. + :param func: The name of the function or method from which the logging call + was invoked. + + .. versionchanged:: 2.5 + *func* was added. + + .. method:: getMessage() + + Returns the message for this :class:`LogRecord` instance after merging any + user-supplied arguments with the message. If the user-supplied message + argument to the logging call is not a string, :func:`str` is called on it to + convert it to a string. This allows use of user-defined classes as + messages, whose ``__str__`` method can return the actual format string to + be used. + + +.. _logrecord-attributes: + +LogRecord attributes +-------------------- + +The LogRecord has a number of attributes, most of which are derived from the +parameters to the constructor. (Note that the names do not always correspond +exactly between the LogRecord constructor parameters and the LogRecord +attributes.) These attributes can be used to merge data from the record into +the format string. The following table lists (in alphabetical order) the +attribute names, their meanings and the corresponding placeholder in a %-style +format string. + ++----------------+-------------------------+-----------------------------------------------+ +| Attribute name | Format | Description | ++================+=========================+===============================================+ +| args | You shouldn't need to | The tuple of arguments merged into ``msg`` to | +| | format this yourself. | produce ``message``. | ++----------------+-------------------------+-----------------------------------------------+ +| asctime | ``%(asctime)s`` | Human-readable time when the | +| | | :class:`LogRecord` was created. By default | +| | | this is of the form '2003-07-08 16:49:45,896' | +| | | (the numbers after the comma are millisecond | +| | | portion of the time). | ++----------------+-------------------------+-----------------------------------------------+ +| created | ``%(created)f`` | Time when the :class:`LogRecord` was created | +| | | (as returned by :func:`time.time`). | ++----------------+-------------------------+-----------------------------------------------+ +| exc_info | You shouldn't need to | Exception tuple (? la ``sys.exc_info``) or, | +| | format this yourself. | if no exception has occurred, *None*. | ++----------------+-------------------------+-----------------------------------------------+ +| filename | ``%(filename)s`` | Filename portion of ``pathname``. | ++----------------+-------------------------+-----------------------------------------------+ +| funcName | ``%(funcName)s`` | Name of function containing the logging call. | ++----------------+-------------------------+-----------------------------------------------+ +| levelname | ``%(levelname)s`` | Text logging level for the message | +| | | (``'DEBUG'``, ``'INFO'``, ``'WARNING'``, | +| | | ``'ERROR'``, ``'CRITICAL'``). | ++----------------+-------------------------+-----------------------------------------------+ +| levelno | ``%(levelno)s`` | Numeric logging level for the message | +| | | (:const:`DEBUG`, :const:`INFO`, | +| | | :const:`WARNING`, :const:`ERROR`, | +| | | :const:`CRITICAL`). | ++----------------+-------------------------+-----------------------------------------------+ +| lineno | ``%(lineno)d`` | Source line number where the logging call was | +| | | issued (if available). | ++----------------+-------------------------+-----------------------------------------------+ +| module | ``%(module)s`` | Module (name portion of ``filename``). | ++----------------+-------------------------+-----------------------------------------------+ +| msecs | ``%(msecs)d`` | Millisecond portion of the time when the | +| | | :class:`LogRecord` was created. | ++----------------+-------------------------+-----------------------------------------------+ +| message | ``%(message)s`` | The logged message, computed as ``msg % | +| | | args``. This is set when | +| | | :meth:`Formatter.format` is invoked. | ++----------------+-------------------------+-----------------------------------------------+ +| msg | You shouldn't need to | The format string passed in the original | +| | format this yourself. | logging call. Merged with ``args`` to | +| | | produce ``message``, or an arbitrary object | +| | | (see :ref:`arbitrary-object-messages`). | ++----------------+-------------------------+-----------------------------------------------+ +| name | ``%(name)s`` | Name of the logger used to log the call. | ++----------------+-------------------------+-----------------------------------------------+ +| pathname | ``%(pathname)s`` | Full pathname of the source file where the | +| | | logging call was issued (if available). | ++----------------+-------------------------+-----------------------------------------------+ +| process | ``%(process)d`` | Process ID (if available). | ++----------------+-------------------------+-----------------------------------------------+ +| processName | ``%(processName)s`` | Process name (if available). | ++----------------+-------------------------+-----------------------------------------------+ +| relativeCreated| ``%(relativeCreated)d`` | Time in milliseconds when the LogRecord was | +| | | created, relative to the time the logging | +| | | module was loaded. | ++----------------+-------------------------+-----------------------------------------------+ +| thread | ``%(thread)d`` | Thread ID (if available). | ++----------------+-------------------------+-----------------------------------------------+ +| threadName | ``%(threadName)s`` | Thread name (if available). | ++----------------+-------------------------+-----------------------------------------------+ + +.. versionchanged:: 2.5 + *funcName* was added. + +.. _logger-adapter: + +LoggerAdapter Objects +--------------------- + +:class:`LoggerAdapter` instances are used to conveniently pass contextual +information into logging calls. For a usage example , see the section on +:ref:`adding contextual information to your logging output `. + +.. versionadded:: 2.6 + + +.. class:: LoggerAdapter(logger, extra) + + Returns an instance of :class:`LoggerAdapter` initialized with an + underlying :class:`Logger` instance and a dict-like object. + + .. method:: process(msg, kwargs) + + Modifies the message and/or keyword arguments passed to a logging call in + order to insert contextual information. This implementation takes the object + passed as *extra* to the constructor and adds it to *kwargs* using key + 'extra'. The return value is a (*msg*, *kwargs*) tuple which has the + (possibly modified) versions of the arguments passed in. + +In addition to the above, :class:`LoggerAdapter` supports the following +methods of :class:`Logger`, i.e. :meth:`debug`, :meth:`info`, :meth:`warning`, +:meth:`error`, :meth:`exception`, :meth:`critical`, :meth:`log`, +:meth:`isEnabledFor`, :meth:`getEffectiveLevel`, :meth:`setLevel`, +:meth:`hasHandlers`. These methods have the same signatures as their +counterparts in :class:`Logger`, so you can use the two types of instances +interchangeably. .. versionchanged:: 2.7 + The :meth:`isEnabledFor` method was added to :class:`LoggerAdapter`. This + method delegates to the underlying logger. -In Python 2.7, a new means of configuring logging has been introduced, using -dictionaries to hold configuration information. This provides a superset of the -functionality of the config-file-based approach outlined above, and is the -recommended configuration method for new applications and deployments. Because -a Python dictionary is used to hold configuration information, and since you -can populate that dictionary using different means, you have more options for -configuration. For example, you can use a configuration file in JSON format, -or, if you have access to YAML processing functionality, a file in YAML -format, to populate the configuration dictionary. Or, of course, you can -construct the dictionary in Python code, receive it in pickled form over a -socket, or use whatever approach makes sense for your application. -Here's an example of the same configuration as above, in YAML format for -the new dictionary-based approach:: +Thread Safety +------------- - version: 1 - formatters: - simple: - format: format=%(asctime)s - %(name)s - %(levelname)s - %(message)s - handlers: - console: - class: logging.StreamHandler - level: DEBUG - formatter: simple - stream: ext://sys.stdout - loggers: - simpleExample: - level: DEBUG - handlers: [console] - propagate: no - root: - level: DEBUG - handlers: [console] +The logging module is intended to be thread-safe without any special work +needing to be done by its clients. It achieves this though using threading +locks; there is one lock to serialize access to the module's shared data, and +each handler also creates a lock to serialize access to its underlying I/O. -For more information about logging using a dictionary, see -:ref:`logging-config-api`. +If you are implementing asynchronous signal handlers using the :mod:`signal` +module, you may not be able to use logging from within such handlers. This is +because lock implementations in the :mod:`threading` module are not always +re-entrant, and so cannot be invoked from such signal handlers. -.. _library-config: - -Configuring Logging for a Library -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -When developing a library which uses logging, some consideration needs to be -given to its configuration. If the using application does not use logging, and -library code makes logging calls, then a one-off message "No handlers could be -found for logger X.Y.Z" is printed to the console. This message is intended -to catch mistakes in logging configuration, but will confuse an application -developer who is not aware of logging by the library. - -In addition to documenting how a library uses logging, a good way to configure -library logging so that it does not cause a spurious message is to add a -handler which does nothing. This avoids the message being printed, since a -handler will be found: it just doesn't produce any output. If the library user -configures logging for application use, presumably that configuration will add -some handlers, and if levels are suitably configured then logging calls made -in library code will send output to those handlers, as normal. - -A do-nothing handler can be simply defined as follows:: - - import logging - - class NullHandler(logging.Handler): - def emit(self, record): - pass - -An instance of this handler should be added to the top-level logger of the -logging namespace used by the library. If all logging by a library *foo* is -done using loggers with names matching "foo.x.y", then the code:: - - import logging - - h = NullHandler() - logging.getLogger("foo").addHandler(h) - -should have the desired effect. If an organisation produces a number of -libraries, then the logger name specified can be "orgname.foo" rather than -just "foo". - -**PLEASE NOTE:** It is strongly advised that you *do not add any handlers other -than* :class:`NullHandler` *to your library's loggers*. This is because the -configuration of handlers is the prerogative of the application developer who -uses your library. The application developer knows their target audience and -what handlers are most appropriate for their application: if you add handlers -"under the hood", you might well interfere with their ability to carry out -unit tests and deliver logs which suit their requirements. - -.. versionadded:: 2.7 - The :class:`NullHandler` class. - - -Logging Levels --------------- - -The numeric values of logging levels are given in the following table. These are -primarily of interest if you want to define your own levels, and need them to -have specific values relative to the predefined levels. If you define a level -with the same numeric value, it overwrites the predefined value; the predefined -name is lost. - -+--------------+---------------+ -| Level | Numeric value | -+==============+===============+ -| ``CRITICAL`` | 50 | -+--------------+---------------+ -| ``ERROR`` | 40 | -+--------------+---------------+ -| ``WARNING`` | 30 | -+--------------+---------------+ -| ``INFO`` | 20 | -+--------------+---------------+ -| ``DEBUG`` | 10 | -+--------------+---------------+ -| ``NOTSET`` | 0 | -+--------------+---------------+ - -Levels can also be associated with loggers, being set either by the developer or -through loading a saved logging configuration. When a logging method is called -on a logger, the logger compares its own level with the level associated with -the method call. If the logger's level is higher than the method call's, no -logging message is actually generated. This is the basic mechanism controlling -the verbosity of logging output. - -Logging messages are encoded as instances of the :class:`LogRecord` class. When -a logger decides to actually log an event, a :class:`LogRecord` instance is -created from the logging message. - -Logging messages are subjected to a dispatch mechanism through the use of -:dfn:`handlers`, which are instances of subclasses of the :class:`Handler` -class. Handlers are responsible for ensuring that a logged message (in the form -of a :class:`LogRecord`) ends up in a particular location (or set of locations) -which is useful for the target audience for that message (such as end users, -support desk staff, system administrators, developers). Handlers are passed -:class:`LogRecord` instances intended for particular destinations. Each logger -can have zero, one or more handlers associated with it (via the -:meth:`addHandler` method of :class:`Logger`). In addition to any handlers -directly associated with a logger, *all handlers associated with all ancestors -of the logger* are called to dispatch the message (unless the *propagate* flag -for a logger is set to a false value, at which point the passing to ancestor -handlers stops). - -Just as for loggers, handlers can have levels associated with them. A handler's -level acts as a filter in the same way as a logger's level does. If a handler -decides to actually dispatch an event, the :meth:`emit` method is used to send -the message to its destination. Most user-defined subclasses of :class:`Handler` -will need to override this :meth:`emit`. - -.. _custom-levels: - -Custom Levels -^^^^^^^^^^^^^ - -Defining your own levels is possible, but should not be necessary, as the -existing levels have been chosen on the basis of practical experience. -However, if you are convinced that you need custom levels, great care should -be exercised when doing this, and it is possibly *a very bad idea to define -custom levels if you are developing a library*. That's because if multiple -library authors all define their own custom levels, there is a chance that -the logging output from such multiple libraries used together will be -difficult for the using developer to control and/or interpret, because a -given numeric value might mean different things for different libraries. - - -Useful Handlers ---------------- - -In addition to the base :class:`Handler` class, many useful subclasses are -provided: - -#. :ref:`stream-handler` instances send error messages to streams (file-like - objects). - -#. :ref:`file-handler` instances send error messages to disk files. - -#. :class:`BaseRotatingHandler` is the base class for handlers that - rotate log files at a certain point. It is not meant to be instantiated - directly. Instead, use :ref:`rotating-file-handler` or - :ref:`timed-rotating-file-handler`. - -#. :ref:`rotating-file-handler` instances send error messages to disk - files, with support for maximum log file sizes and log file rotation. - -#. :ref:`timed-rotating-file-handler` instances send error messages to - disk files, rotating the log file at certain timed intervals. - -#. :ref:`socket-handler` instances send error messages to TCP/IP - sockets. - -#. :ref:`datagram-handler` instances send error messages to UDP - sockets. - -#. :ref:`smtp-handler` instances send error messages to a designated - email address. - -#. :ref:`syslog-handler` instances send error messages to a Unix - syslog daemon, possibly on a remote machine. - -#. :ref:`nt-eventlog-handler` instances send error messages to a - Windows NT/2000/XP event log. - -#. :ref:`memory-handler` instances send error messages to a buffer - in memory, which is flushed whenever specific criteria are met. - -#. :ref:`http-handler` instances send error messages to an HTTP - server using either ``GET`` or ``POST`` semantics. - -#. :ref:`watched-file-handler` instances watch the file they are - logging to. If the file changes, it is closed and reopened using the file - name. This handler is only useful on Unix-like systems; Windows does not - support the underlying mechanism used. - -#. :ref:`null-handler` instances do nothing with error messages. They are used - by library developers who want to use logging, but want to avoid the "No - handlers could be found for logger XXX" message which can be displayed if - the library user has not configured logging. See :ref:`library-config` for - more information. - -.. versionadded:: 2.7 - The :class:`NullHandler` class. - -The :class:`NullHandler`, :class:`StreamHandler` and :class:`FileHandler` -classes are defined in the core logging package. The other handlers are -defined in a sub- module, :mod:`logging.handlers`. (There is also another -sub-module, :mod:`logging.config`, for configuration functionality.) - -Logged messages are formatted for presentation through instances of the -:class:`Formatter` class. They are initialized with a format string suitable for -use with the % operator and a dictionary. - -For formatting multiple messages in a batch, instances of -:class:`BufferingFormatter` can be used. In addition to the format string (which -is applied to each message in the batch), there is provision for header and -trailer format strings. - -When filtering based on logger level and/or handler level is not enough, -instances of :class:`Filter` can be added to both :class:`Logger` and -:class:`Handler` instances (through their :meth:`addFilter` method). Before -deciding to process a message further, both loggers and handlers consult all -their filters for permission. If any filter returns a false value, the message -is not processed further. - -The basic :class:`Filter` functionality allows filtering by specific logger -name. If this feature is used, messages sent to the named logger and its -children are allowed through the filter, and all others dropped. Module-Level Functions ---------------------- @@ -928,9 +883,36 @@ which need to use custom logger behavior. +Integration with the warnings module +------------------------------------ + +The :func:`captureWarnings` function can be used to integrate :mod:`logging` +with the :mod:`warnings` module. + +.. function:: captureWarnings(capture) + + This function is used to turn the capture of warnings by logging on and + off. + + If *capture* is ``True``, warnings issued by the :mod:`warnings` module will + be redirected to the logging system. Specifically, a warning will be + formatted using :func:`warnings.formatwarning` and the resulting string + logged to a logger named 'py.warnings' with a severity of `WARNING`. + + If *capture* is ``False``, the redirection of warnings to the logging system + will stop, and warnings will be redirected to their original destinations + (i.e. those in effect before `captureWarnings(True)` was called). + + .. seealso:: + Module :mod:`logging.config` + Configuration API for the logging module. + + Module :mod:`logging.handlers` + Useful handlers included with the logging module. + :pep:`282` - A Logging System The proposal which described this feature for inclusion in the Python standard library. @@ -941,2767 +923,3 @@ and 2.2.x, which do not include the :mod:`logging` package in the standard library. -.. _logger: - -Logger Objects --------------- - -Loggers have the following attributes and methods. Note that Loggers are never -instantiated directly, but always through the module-level function -``logging.getLogger(name)``. - - -.. attribute:: Logger.propagate - - If this evaluates to false, logging messages are not passed by this logger or by - its child loggers to the handlers of higher level (ancestor) loggers. The - constructor sets this attribute to 1. - - -.. method:: Logger.setLevel(lvl) - - Sets the threshold for this logger to *lvl*. Logging messages which are less - severe than *lvl* will be ignored. When a logger is created, the level is set to - :const:`NOTSET` (which causes all messages to be processed when the logger is - the root logger, or delegation to the parent when the logger is a non-root - logger). Note that the root logger is created with level :const:`WARNING`. - - The term "delegation to the parent" means that if a logger has a level of - NOTSET, its chain of ancestor loggers is traversed until either an ancestor with - a level other than NOTSET is found, or the root is reached. - - If an ancestor is found with a level other than NOTSET, then that ancestor's - level is treated as the effective level of the logger where the ancestor search - began, and is used to determine how a logging event is handled. - - If the root is reached, and it has a level of NOTSET, then all messages will be - processed. Otherwise, the root's level will be used as the effective level. - - -.. method:: Logger.isEnabledFor(lvl) - - Indicates if a message of severity *lvl* would be processed by this logger. - This method checks first the module-level level set by - ``logging.disable(lvl)`` and then the logger's effective level as determined - by :meth:`getEffectiveLevel`. - - -.. method:: Logger.getEffectiveLevel() - - Indicates the effective level for this logger. If a value other than - :const:`NOTSET` has been set using :meth:`setLevel`, it is returned. Otherwise, - the hierarchy is traversed towards the root until a value other than - :const:`NOTSET` is found, and that value is returned. - - -.. method:: Logger.getChild(suffix) - - Returns a logger which is a descendant to this logger, as determined by the suffix. - Thus, ``logging.getLogger('abc').getChild('def.ghi')`` would return the same - logger as would be returned by ``logging.getLogger('abc.def.ghi')``. This is a - convenience method, useful when the parent logger is named using e.g. ``__name__`` - rather than a literal string. - - .. versionadded:: 2.7 - -.. method:: Logger.debug(msg[, *args[, **kwargs]]) - - Logs a message with level :const:`DEBUG` on this logger. The *msg* is the - message format string, and the *args* are the arguments which are merged into - *msg* using the string formatting operator. (Note that this means that you can - use keywords in the format string, together with a single dictionary argument.) - - There are two keyword arguments in *kwargs* which are inspected: *exc_info* - which, if it does not evaluate as false, causes exception information to be - added to the logging message. If an exception tuple (in the format returned by - :func:`sys.exc_info`) is provided, it is used; otherwise, :func:`sys.exc_info` - is called to get the exception information. - - The other optional keyword argument is *extra* which can be used to pass a - dictionary which is used to populate the __dict__ of the LogRecord created for - the logging event with user-defined attributes. These custom attributes can then - be used as you like. For example, they could be incorporated into logged - messages. For example:: - - FORMAT = "%(asctime)-15s %(clientip)s %(user)-8s %(message)s" - logging.basicConfig(format=FORMAT) - d = { 'clientip' : '192.168.0.1', 'user' : 'fbloggs' } - logger = logging.getLogger("tcpserver") - logger.warning("Protocol problem: %s", "connection reset", extra=d) - - would print something like :: - - 2006-02-08 22:20:02,165 192.168.0.1 fbloggs Protocol problem: connection reset - - The keys in the dictionary passed in *extra* should not clash with the keys used - by the logging system. (See the :class:`Formatter` documentation for more - information on which keys are used by the logging system.) - - If you choose to use these attributes in logged messages, you need to exercise - some care. In the above example, for instance, the :class:`Formatter` has been - set up with a format string which expects 'clientip' and 'user' in the attribute - dictionary of the LogRecord. If these are missing, the message will not be - logged because a string formatting exception will occur. So in this case, you - always need to pass the *extra* dictionary with these keys. - - While this might be annoying, this feature is intended for use in specialized - circumstances, such as multi-threaded servers where the same code executes in - many contexts, and interesting conditions which arise are dependent on this - context (such as remote client IP address and authenticated user name, in the - above example). In such circumstances, it is likely that specialized - :class:`Formatter`\ s would be used with particular :class:`Handler`\ s. - - .. versionchanged:: 2.5 - *extra* was added. - - -.. method:: Logger.info(msg[, *args[, **kwargs]]) - - Logs a message with level :const:`INFO` on this logger. The arguments are - interpreted as for :meth:`debug`. - - -.. method:: Logger.warning(msg[, *args[, **kwargs]]) - - Logs a message with level :const:`WARNING` on this logger. The arguments are - interpreted as for :meth:`debug`. - - -.. method:: Logger.error(msg[, *args[, **kwargs]]) - - Logs a message with level :const:`ERROR` on this logger. The arguments are - interpreted as for :meth:`debug`. - - -.. method:: Logger.critical(msg[, *args[, **kwargs]]) - - Logs a message with level :const:`CRITICAL` on this logger. The arguments are - interpreted as for :meth:`debug`. - - -.. method:: Logger.log(lvl, msg[, *args[, **kwargs]]) - - Logs a message with integer level *lvl* on this logger. The other arguments are - interpreted as for :meth:`debug`. - - -.. method:: Logger.exception(msg[, *args]) - - Logs a message with level :const:`ERROR` on this logger. The arguments are - interpreted as for :meth:`debug`. Exception info is added to the logging - message. This method should only be called from an exception handler. - - -.. method:: Logger.addFilter(filt) - - Adds the specified filter *filt* to this logger. - - -.. method:: Logger.removeFilter(filt) - - Removes the specified filter *filt* from this logger. - - -.. method:: Logger.filter(record) - - Applies this logger's filters to the record and returns a true value if the - record is to be processed. - - -.. method:: Logger.addHandler(hdlr) - - Adds the specified handler *hdlr* to this logger. - - -.. method:: Logger.removeHandler(hdlr) - - Removes the specified handler *hdlr* from this logger. - - -.. method:: Logger.findCaller() - - Finds the caller's source filename and line number. Returns the filename, line - number and function name as a 3-element tuple. - - .. versionchanged:: 2.4 - The function name was added. In earlier versions, the filename and line number - were returned as a 2-element tuple.. - - -.. method:: Logger.handle(record) - - Handles a record by passing it to all handlers associated with this logger and - its ancestors (until a false value of *propagate* is found). This method is used - for unpickled records received from a socket, as well as those created locally. - Logger-level filtering is applied using :meth:`~Logger.filter`. - - -.. method:: Logger.makeRecord(name, lvl, fn, lno, msg, args, exc_info [, func, extra]) - - This is a factory method which can be overridden in subclasses to create - specialized :class:`LogRecord` instances. - - .. versionchanged:: 2.5 - *func* and *extra* were added. - - -.. _minimal-example: - -Basic example -------------- - -.. versionchanged:: 2.4 - formerly :func:`basicConfig` did not take any keyword arguments. - -The :mod:`logging` package provides a lot of flexibility, and its configuration -can appear daunting. This section demonstrates that simple use of the logging -package is possible. - -The simplest example shows logging to the console:: - - import logging - - logging.debug('A debug message') - logging.info('Some information') - logging.warning('A shot across the bows') - -If you run the above script, you'll see this:: - - WARNING:root:A shot across the bows - -Because no particular logger was specified, the system used the root logger. The -debug and info messages didn't appear because by default, the root logger is -configured to only handle messages with a severity of WARNING or above. The -message format is also a configuration default, as is the output destination of -the messages - ``sys.stderr``. The severity level, the message format and -destination can be easily changed, as shown in the example below:: - - import logging - - logging.basicConfig(level=logging.DEBUG, - format='%(asctime)s %(levelname)s %(message)s', - filename='myapp.log', - filemode='w') - logging.debug('A debug message') - logging.info('Some information') - logging.warning('A shot across the bows') - -The :meth:`basicConfig` method is used to change the configuration defaults, -which results in output (written to ``myapp.log``) which should look -something like the following:: - - 2004-07-02 13:00:08,743 DEBUG A debug message - 2004-07-02 13:00:08,743 INFO Some information - 2004-07-02 13:00:08,743 WARNING A shot across the bows - -This time, all messages with a severity of DEBUG or above were handled, and the -format of the messages was also changed, and output went to the specified file -rather than the console. - -Formatting uses standard Python string formatting - see section -:ref:`string-formatting`. The format string takes the following common -specifiers. For a complete list of specifiers, consult the :class:`Formatter` -documentation. - -+-------------------+-----------------------------------------------+ -| Format | Description | -+===================+===============================================+ -| ``%(name)s`` | Name of the logger (logging channel). | -+-------------------+-----------------------------------------------+ -| ``%(levelname)s`` | Text logging level for the message | -| | (``'DEBUG'``, ``'INFO'``, ``'WARNING'``, | -| | ``'ERROR'``, ``'CRITICAL'``). | -+-------------------+-----------------------------------------------+ -| ``%(asctime)s`` | Human-readable time when the | -| | :class:`LogRecord` was created. By default | -| | this is of the form "2003-07-08 16:49:45,896" | -| | (the numbers after the comma are millisecond | -| | portion of the time). | -+-------------------+-----------------------------------------------+ -| ``%(message)s`` | The logged message. | -+-------------------+-----------------------------------------------+ - -To change the date/time format, you can pass an additional keyword parameter, -*datefmt*, as in the following:: - - import logging - - logging.basicConfig(level=logging.DEBUG, - format='%(asctime)s %(levelname)-8s %(message)s', - datefmt='%a, %d %b %Y %H:%M:%S', - filename='/temp/myapp.log', - filemode='w') - logging.debug('A debug message') - logging.info('Some information') - logging.warning('A shot across the bows') - -which would result in output like :: - - Fri, 02 Jul 2004 13:06:18 DEBUG A debug message - Fri, 02 Jul 2004 13:06:18 INFO Some information - Fri, 02 Jul 2004 13:06:18 WARNING A shot across the bows - -The date format string follows the requirements of :func:`strftime` - see the -documentation for the :mod:`time` module. - -If, instead of sending logging output to the console or a file, you'd rather use -a file-like object which you have created separately, you can pass it to -:func:`basicConfig` using the *stream* keyword argument. Note that if both -*stream* and *filename* keyword arguments are passed, the *stream* argument is -ignored. - -Of course, you can put variable information in your output. To do this, simply -have the message be a format string and pass in additional arguments containing -the variable information, as in the following example:: - - import logging - - logging.basicConfig(level=logging.DEBUG, - format='%(asctime)s %(levelname)-8s %(message)s', - datefmt='%a, %d %b %Y %H:%M:%S', - filename='/temp/myapp.log', - filemode='w') - logging.error('Pack my box with %d dozen %s', 5, 'liquor jugs') - -which would result in :: - - Wed, 21 Jul 2004 15:35:16 ERROR Pack my box with 5 dozen liquor jugs - - -.. _multiple-destinations: - -Logging to multiple destinations --------------------------------- - -Let's say you want to log to console and file with different message formats and -in differing circumstances. Say you want to log messages with levels of DEBUG -and higher to file, and those messages at level INFO and higher to the console. -Let's also assume that the file should contain timestamps, but the console -messages should not. Here's how you can achieve this:: - - import logging - - # set up logging to file - see previous section for more details - logging.basicConfig(level=logging.DEBUG, - format='%(asctime)s %(name)-12s %(levelname)-8s %(message)s', - datefmt='%m-%d %H:%M', - filename='/temp/myapp.log', - filemode='w') - # define a Handler which writes INFO messages or higher to the sys.stderr - console = logging.StreamHandler() - console.setLevel(logging.INFO) - # set a format which is simpler for console use - formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s') - # tell the handler to use this format - console.setFormatter(formatter) - # add the handler to the root logger - logging.getLogger('').addHandler(console) - - # Now, we can log to the root logger, or any other logger. First the root... - logging.info('Jackdaws love my big sphinx of quartz.') - - # Now, define a couple of other loggers which might represent areas in your - # application: - - logger1 = logging.getLogger('myapp.area1') - logger2 = logging.getLogger('myapp.area2') - - logger1.debug('Quick zephyrs blow, vexing daft Jim.') - logger1.info('How quickly daft jumping zebras vex.') - logger2.warning('Jail zesty vixen who grabbed pay from quack.') - logger2.error('The five boxing wizards jump quickly.') - -When you run this, on the console you will see :: - - root : INFO Jackdaws love my big sphinx of quartz. - myapp.area1 : INFO How quickly daft jumping zebras vex. - myapp.area2 : WARNING Jail zesty vixen who grabbed pay from quack. - myapp.area2 : ERROR The five boxing wizards jump quickly. - -and in the file you will see something like :: - - 10-22 22:19 root INFO Jackdaws love my big sphinx of quartz. - 10-22 22:19 myapp.area1 DEBUG Quick zephyrs blow, vexing daft Jim. - 10-22 22:19 myapp.area1 INFO How quickly daft jumping zebras vex. - 10-22 22:19 myapp.area2 WARNING Jail zesty vixen who grabbed pay from quack. - 10-22 22:19 myapp.area2 ERROR The five boxing wizards jump quickly. - -As you can see, the DEBUG message only shows up in the file. The other messages -are sent to both destinations. - -This example uses console and file handlers, but you can use any number and -combination of handlers you choose. - -.. _logging-exceptions: - -Exceptions raised during logging --------------------------------- - -The logging package is designed to swallow exceptions which occur while logging -in production. This is so that errors which occur while handling logging events -- such as logging misconfiguration, network or other similar errors - do not -cause the application using logging to terminate prematurely. - -:class:`SystemExit` and :class:`KeyboardInterrupt` exceptions are never -swallowed. Other exceptions which occur during the :meth:`emit` method of a -:class:`Handler` subclass are passed to its :meth:`handleError` method. - -The default implementation of :meth:`handleError` in :class:`Handler` checks -to see if a module-level variable, :data:`raiseExceptions`, is set. If set, a -traceback is printed to :data:`sys.stderr`. If not set, the exception is swallowed. - -**Note:** The default value of :data:`raiseExceptions` is ``True``. This is because -during development, you typically want to be notified of any exceptions that -occur. It's advised that you set :data:`raiseExceptions` to ``False`` for production -usage. - -.. _context-info: - -Adding contextual information to your logging output ----------------------------------------------------- - -Sometimes you want logging output to contain contextual information in -addition to the parameters passed to the logging call. For example, in a -networked application, it may be desirable to log client-specific information -in the log (e.g. remote client's username, or IP address). Although you could -use the *extra* parameter to achieve this, it's not always convenient to pass -the information in this way. While it might be tempting to create -:class:`Logger` instances on a per-connection basis, this is not a good idea -because these instances are not garbage collected. While this is not a problem -in practice, when the number of :class:`Logger` instances is dependent on the -level of granularity you want to use in logging an application, it could -be hard to manage if the number of :class:`Logger` instances becomes -effectively unbounded. - - -Using LoggerAdapters to impart contextual information -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -An easy way in which you can pass contextual information to be output along -with logging event information is to use the :class:`LoggerAdapter` class. -This class is designed to look like a :class:`Logger`, so that you can call -:meth:`debug`, :meth:`info`, :meth:`warning`, :meth:`error`, -:meth:`exception`, :meth:`critical` and :meth:`log`. These methods have the -same signatures as their counterparts in :class:`Logger`, so you can use the -two types of instances interchangeably. - -When you create an instance of :class:`LoggerAdapter`, you pass it a -:class:`Logger` instance and a dict-like object which contains your contextual -information. When you call one of the logging methods on an instance of -:class:`LoggerAdapter`, it delegates the call to the underlying instance of -:class:`Logger` passed to its constructor, and arranges to pass the contextual -information in the delegated call. Here's a snippet from the code of -:class:`LoggerAdapter`:: - - def debug(self, msg, *args, **kwargs): - """ - Delegate a debug call to the underlying logger, after adding - contextual information from this adapter instance. - """ - msg, kwargs = self.process(msg, kwargs) - self.logger.debug(msg, *args, **kwargs) - -The :meth:`process` method of :class:`LoggerAdapter` is where the contextual -information is added to the logging output. It's passed the message and -keyword arguments of the logging call, and it passes back (potentially) -modified versions of these to use in the call to the underlying logger. The -default implementation of this method leaves the message alone, but inserts -an "extra" key in the keyword argument whose value is the dict-like object -passed to the constructor. Of course, if you had passed an "extra" keyword -argument in the call to the adapter, it will be silently overwritten. - -The advantage of using "extra" is that the values in the dict-like object are -merged into the :class:`LogRecord` instance's __dict__, allowing you to use -customized strings with your :class:`Formatter` instances which know about -the keys of the dict-like object. If you need a different method, e.g. if you -want to prepend or append the contextual information to the message string, -you just need to subclass :class:`LoggerAdapter` and override :meth:`process` -to do what you need. Here's an example script which uses this class, which -also illustrates what dict-like behaviour is needed from an arbitrary -"dict-like" object for use in the constructor:: - - import logging - - class ConnInfo: - """ - An example class which shows how an arbitrary class can be used as - the 'extra' context information repository passed to a LoggerAdapter. - """ - - def __getitem__(self, name): - """ - To allow this instance to look like a dict. - """ - from random import choice - if name == "ip": - result = choice(["127.0.0.1", "192.168.0.1"]) - elif name == "user": - result = choice(["jim", "fred", "sheila"]) - else: - result = self.__dict__.get(name, "?") - return result - - def __iter__(self): - """ - To allow iteration over keys, which will be merged into - the LogRecord dict before formatting and output. - """ - keys = ["ip", "user"] - keys.extend(self.__dict__.keys()) - return keys.__iter__() - - if __name__ == "__main__": - from random import choice - levels = (logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR, logging.CRITICAL) - a1 = logging.LoggerAdapter(logging.getLogger("a.b.c"), - { "ip" : "123.231.231.123", "user" : "sheila" }) - logging.basicConfig(level=logging.DEBUG, - format="%(asctime)-15s %(name)-5s %(levelname)-8s IP: %(ip)-15s User: %(user)-8s %(message)s") - a1.debug("A debug message") - a1.info("An info message with %s", "some parameters") - a2 = logging.LoggerAdapter(logging.getLogger("d.e.f"), ConnInfo()) - for x in range(10): - lvl = choice(levels) - lvlname = logging.getLevelName(lvl) - a2.log(lvl, "A message at %s level with %d %s", lvlname, 2, "parameters") - -When this script is run, the output should look something like this:: - - 2008-01-18 14:49:54,023 a.b.c DEBUG IP: 123.231.231.123 User: sheila A debug message - 2008-01-18 14:49:54,023 a.b.c INFO IP: 123.231.231.123 User: sheila An info message with some parameters - 2008-01-18 14:49:54,023 d.e.f CRITICAL IP: 192.168.0.1 User: jim A message at CRITICAL level with 2 parameters - 2008-01-18 14:49:54,033 d.e.f INFO IP: 192.168.0.1 User: jim A message at INFO level with 2 parameters - 2008-01-18 14:49:54,033 d.e.f WARNING IP: 192.168.0.1 User: sheila A message at WARNING level with 2 parameters - 2008-01-18 14:49:54,033 d.e.f ERROR IP: 127.0.0.1 User: fred A message at ERROR level with 2 parameters - 2008-01-18 14:49:54,033 d.e.f ERROR IP: 127.0.0.1 User: sheila A message at ERROR level with 2 parameters - 2008-01-18 14:49:54,033 d.e.f WARNING IP: 192.168.0.1 User: sheila A message at WARNING level with 2 parameters - 2008-01-18 14:49:54,033 d.e.f WARNING IP: 192.168.0.1 User: jim A message at WARNING level with 2 parameters - 2008-01-18 14:49:54,033 d.e.f INFO IP: 192.168.0.1 User: fred A message at INFO level with 2 parameters - 2008-01-18 14:49:54,033 d.e.f WARNING IP: 192.168.0.1 User: sheila A message at WARNING level with 2 parameters - 2008-01-18 14:49:54,033 d.e.f WARNING IP: 127.0.0.1 User: jim A message at WARNING level with 2 parameters - -.. versionadded:: 2.6 - -The :class:`LoggerAdapter` class was not present in previous versions. - -.. _filters-contextual: - -Using Filters to impart contextual information -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -You can also add contextual information to log output using a user-defined -:class:`Filter`. ``Filter`` instances are allowed to modify the ``LogRecords`` -passed to them, including adding additional attributes which can then be output -using a suitable format string, or if needed a custom :class:`Formatter`. - -For example in a web application, the request being processed (or at least, -the interesting parts of it) can be stored in a threadlocal -(:class:`threading.local`) variable, and then accessed from a ``Filter`` to -add, say, information from the request - say, the remote IP address and remote -user's username - to the ``LogRecord``, using the attribute names 'ip' and -'user' as in the ``LoggerAdapter`` example above. In that case, the same format -string can be used to get similar output to that shown above. Here's an example -script:: - - import logging - from random import choice - - class ContextFilter(logging.Filter): - """ - This is a filter which injects contextual information into the log. - - Rather than use actual contextual information, we just use random - data in this demo. - """ - - USERS = ['jim', 'fred', 'sheila'] - IPS = ['123.231.231.123', '127.0.0.1', '192.168.0.1'] - - def filter(self, record): - - record.ip = choice(ContextFilter.IPS) - record.user = choice(ContextFilter.USERS) - return True - - if __name__ == "__main__": - levels = (logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR, logging.CRITICAL) - a1 = logging.LoggerAdapter(logging.getLogger("a.b.c"), - { "ip" : "123.231.231.123", "user" : "sheila" }) - logging.basicConfig(level=logging.DEBUG, - format="%(asctime)-15s %(name)-5s %(levelname)-8s IP: %(ip)-15s User: %(user)-8s %(message)s") - a1 = logging.getLogger("a.b.c") - a2 = logging.getLogger("d.e.f") - - f = ContextFilter() - a1.addFilter(f) - a2.addFilter(f) - a1.debug("A debug message") - a1.info("An info message with %s", "some parameters") - for x in range(10): - lvl = choice(levels) - lvlname = logging.getLevelName(lvl) - a2.log(lvl, "A message at %s level with %d %s", lvlname, 2, "parameters") - -which, when run, produces something like:: - - 2010-09-06 22:38:15,292 a.b.c DEBUG IP: 123.231.231.123 User: fred A debug message - 2010-09-06 22:38:15,300 a.b.c INFO IP: 192.168.0.1 User: sheila An info message with some parameters - 2010-09-06 22:38:15,300 d.e.f CRITICAL IP: 127.0.0.1 User: sheila A message at CRITICAL level with 2 parameters - 2010-09-06 22:38:15,300 d.e.f ERROR IP: 127.0.0.1 User: jim A message at ERROR level with 2 parameters - 2010-09-06 22:38:15,300 d.e.f DEBUG IP: 127.0.0.1 User: sheila A message at DEBUG level with 2 parameters - 2010-09-06 22:38:15,300 d.e.f ERROR IP: 123.231.231.123 User: fred A message at ERROR level with 2 parameters - 2010-09-06 22:38:15,300 d.e.f CRITICAL IP: 192.168.0.1 User: jim A message at CRITICAL level with 2 parameters - 2010-09-06 22:38:15,300 d.e.f CRITICAL IP: 127.0.0.1 User: sheila A message at CRITICAL level with 2 parameters - 2010-09-06 22:38:15,300 d.e.f DEBUG IP: 192.168.0.1 User: jim A message at DEBUG level with 2 parameters - 2010-09-06 22:38:15,301 d.e.f ERROR IP: 127.0.0.1 User: sheila A message at ERROR level with 2 parameters - 2010-09-06 22:38:15,301 d.e.f DEBUG IP: 123.231.231.123 User: fred A message at DEBUG level with 2 parameters - 2010-09-06 22:38:15,301 d.e.f INFO IP: 123.231.231.123 User: fred A message at INFO level with 2 parameters - - -.. _multiple-processes: - -Logging to a single file from multiple processes ------------------------------------------------- - -Although logging is thread-safe, and logging to a single file from multiple -threads in a single process *is* supported, logging to a single file from -*multiple processes* is *not* supported, because there is no standard way to -serialize access to a single file across multiple processes in Python. If you -need to log to a single file from multiple processes, the best way of doing -this is to have all the processes log to a :class:`SocketHandler`, and have a -separate process which implements a socket server which reads from the socket -and logs to file. (If you prefer, you can dedicate one thread in one of the -existing processes to perform this function.) The following section documents -this approach in more detail and includes a working socket receiver which can -be used as a starting point for you to adapt in your own applications. - -If you are using a recent version of Python which includes the -:mod:`multiprocessing` module, you can write your own handler which uses the -:class:`Lock` class from this module to serialize access to the file from -your processes. The existing :class:`FileHandler` and subclasses do not make -use of :mod:`multiprocessing` at present, though they may do so in the future. -Note that at present, the :mod:`multiprocessing` module does not provide -working lock functionality on all platforms (see -http://bugs.python.org/issue3770). - -.. _network-logging: - -Sending and receiving logging events across a network ------------------------------------------------------ - -Let's say you want to send logging events across a network, and handle them at -the receiving end. A simple way of doing this is attaching a -:class:`SocketHandler` instance to the root logger at the sending end:: - - import logging, logging.handlers - - rootLogger = logging.getLogger('') - rootLogger.setLevel(logging.DEBUG) - socketHandler = logging.handlers.SocketHandler('localhost', - logging.handlers.DEFAULT_TCP_LOGGING_PORT) - # don't bother with a formatter, since a socket handler sends the event as - # an unformatted pickle - rootLogger.addHandler(socketHandler) - - # Now, we can log to the root logger, or any other logger. First the root... - logging.info('Jackdaws love my big sphinx of quartz.') - - # Now, define a couple of other loggers which might represent areas in your - # application: - - logger1 = logging.getLogger('myapp.area1') - logger2 = logging.getLogger('myapp.area2') - - logger1.debug('Quick zephyrs blow, vexing daft Jim.') - logger1.info('How quickly daft jumping zebras vex.') - logger2.warning('Jail zesty vixen who grabbed pay from quack.') - logger2.error('The five boxing wizards jump quickly.') - -At the receiving end, you can set up a receiver using the :mod:`SocketServer` -module. Here is a basic working example:: - - import cPickle - import logging - import logging.handlers - import SocketServer - import struct - - - class LogRecordStreamHandler(SocketServer.StreamRequestHandler): - """Handler for a streaming logging request. - - This basically logs the record using whatever logging policy is - configured locally. - """ - - def handle(self): - """ - Handle multiple requests - each expected to be a 4-byte length, - followed by the LogRecord in pickle format. Logs the record - according to whatever policy is configured locally. - """ - while 1: - chunk = self.connection.recv(4) - if len(chunk) < 4: - break - slen = struct.unpack(">L", chunk)[0] - chunk = self.connection.recv(slen) - while len(chunk) < slen: - chunk = chunk + self.connection.recv(slen - len(chunk)) - obj = self.unPickle(chunk) - record = logging.makeLogRecord(obj) - self.handleLogRecord(record) - - def unPickle(self, data): - return cPickle.loads(data) - - def handleLogRecord(self, record): - # if a name is specified, we use the named logger rather than the one - # implied by the record. - if self.server.logname is not None: - name = self.server.logname - else: - name = record.name - logger = logging.getLogger(name) - # N.B. EVERY record gets logged. This is because Logger.handle - # is normally called AFTER logger-level filtering. If you want - # to do filtering, do it at the client end to save wasting - # cycles and network bandwidth! - logger.handle(record) - - class LogRecordSocketReceiver(SocketServer.ThreadingTCPServer): - """simple TCP socket-based logging receiver suitable for testing. - """ - - allow_reuse_address = 1 - - def __init__(self, host='localhost', - port=logging.handlers.DEFAULT_TCP_LOGGING_PORT, - handler=LogRecordStreamHandler): - SocketServer.ThreadingTCPServer.__init__(self, (host, port), handler) - self.abort = 0 - self.timeout = 1 - self.logname = None - - def serve_until_stopped(self): - import select - abort = 0 - while not abort: - rd, wr, ex = select.select([self.socket.fileno()], - [], [], - self.timeout) - if rd: - self.handle_request() - abort = self.abort - - def main(): - logging.basicConfig( - format="%(relativeCreated)5d %(name)-15s %(levelname)-8s %(message)s") - tcpserver = LogRecordSocketReceiver() - print "About to start TCP server..." - tcpserver.serve_until_stopped() - - if __name__ == "__main__": - main() - -First run the server, and then the client. On the client side, nothing is -printed on the console; on the server side, you should see something like:: - - About to start TCP server... - 59 root INFO Jackdaws love my big sphinx of quartz. - 59 myapp.area1 DEBUG Quick zephyrs blow, vexing daft Jim. - 69 myapp.area1 INFO How quickly daft jumping zebras vex. - 69 myapp.area2 WARNING Jail zesty vixen who grabbed pay from quack. - 69 myapp.area2 ERROR The five boxing wizards jump quickly. - -Note that there are some security issues with pickle in some scenarios. If -these affect you, you can use an alternative serialization scheme by overriding -the :meth:`makePickle` method and implementing your alternative there, as -well as adapting the above script to use your alternative serialization. - -.. _arbitrary-object-messages: - -Using arbitrary objects as messages ------------------------------------ - -In the preceding sections and examples, it has been assumed that the message -passed when logging the event is a string. However, this is not the only -possibility. You can pass an arbitrary object as a message, and its -:meth:`__str__` method will be called when the logging system needs to convert -it to a string representation. In fact, if you want to, you can avoid -computing a string representation altogether - for example, the -:class:`SocketHandler` emits an event by pickling it and sending it over the -wire. - -Optimization ------------- - -Formatting of message arguments is deferred until it cannot be avoided. -However, computing the arguments passed to the logging method can also be -expensive, and you may want to avoid doing it if the logger will just throw -away your event. To decide what to do, you can call the :meth:`isEnabledFor` -method which takes a level argument and returns true if the event would be -created by the Logger for that level of call. You can write code like this:: - - if logger.isEnabledFor(logging.DEBUG): - logger.debug("Message with %s, %s", expensive_func1(), - expensive_func2()) - -so that if the logger's threshold is set above ``DEBUG``, the calls to -:func:`expensive_func1` and :func:`expensive_func2` are never made. - -There are other optimizations which can be made for specific applications which -need more precise control over what logging information is collected. Here's a -list of things you can do to avoid processing during logging which you don't -need: - -+-----------------------------------------------+----------------------------------------+ -| What you don't want to collect | How to avoid collecting it | -+===============================================+========================================+ -| Information about where calls were made from. | Set ``logging._srcfile`` to ``None``. | -+-----------------------------------------------+----------------------------------------+ -| Threading information. | Set ``logging.logThreads`` to ``0``. | -+-----------------------------------------------+----------------------------------------+ -| Process information. | Set ``logging.logProcesses`` to ``0``. | -+-----------------------------------------------+----------------------------------------+ - -Also note that the core logging module only includes the basic handlers. If -you don't import :mod:`logging.handlers` and :mod:`logging.config`, they won't -take up any memory. - -.. _handler: - -Handler Objects ---------------- - -Handlers have the following attributes and methods. Note that :class:`Handler` -is never instantiated directly; this class acts as a base for more useful -subclasses. However, the :meth:`__init__` method in subclasses needs to call -:meth:`Handler.__init__`. - - -.. method:: Handler.__init__(level=NOTSET) - - Initializes the :class:`Handler` instance by setting its level, setting the list - of filters to the empty list and creating a lock (using :meth:`createLock`) for - serializing access to an I/O mechanism. - - -.. method:: Handler.createLock() - - Initializes a thread lock which can be used to serialize access to underlying - I/O functionality which may not be threadsafe. - - -.. method:: Handler.acquire() - - Acquires the thread lock created with :meth:`createLock`. - - -.. method:: Handler.release() - - Releases the thread lock acquired with :meth:`acquire`. - - -.. method:: Handler.setLevel(lvl) - - Sets the threshold for this handler to *lvl*. Logging messages which are less - severe than *lvl* will be ignored. When a handler is created, the level is set - to :const:`NOTSET` (which causes all messages to be processed). - - -.. method:: Handler.setFormatter(form) - - Sets the :class:`Formatter` for this handler to *form*. - - -.. method:: Handler.addFilter(filt) - - Adds the specified filter *filt* to this handler. - - -.. method:: Handler.removeFilter(filt) - - Removes the specified filter *filt* from this handler. - - -.. method:: Handler.filter(record) - - Applies this handler's filters to the record and returns a true value if the - record is to be processed. - - -.. method:: Handler.flush() - - Ensure all logging output has been flushed. This version does nothing and is - intended to be implemented by subclasses. - - -.. method:: Handler.close() - - Tidy up any resources used by the handler. This version does no output but - removes the handler from an internal list of handlers which is closed when - :func:`shutdown` is called. Subclasses should ensure that this gets called - from overridden :meth:`close` methods. - - -.. method:: Handler.handle(record) - - Conditionally emits the specified logging record, depending on filters which may - have been added to the handler. Wraps the actual emission of the record with - acquisition/release of the I/O thread lock. - - -.. method:: Handler.handleError(record) - - This method should be called from handlers when an exception is encountered - during an :meth:`emit` call. By default it does nothing, which means that - exceptions get silently ignored. This is what is mostly wanted for a logging - system - most users will not care about errors in the logging system, they are - more interested in application errors. You could, however, replace this with a - custom handler if you wish. The specified record is the one which was being - processed when the exception occurred. - - -.. method:: Handler.format(record) - - Do formatting for a record - if a formatter is set, use it. Otherwise, use the - default formatter for the module. - - -.. method:: Handler.emit(record) - - Do whatever it takes to actually log the specified logging record. This version - is intended to be implemented by subclasses and so raises a - :exc:`NotImplementedError`. - - -.. _stream-handler: - -StreamHandler -^^^^^^^^^^^^^ - -The :class:`StreamHandler` class, located in the core :mod:`logging` package, -sends logging output to streams such as *sys.stdout*, *sys.stderr* or any -file-like object (or, more precisely, any object which supports :meth:`write` -and :meth:`flush` methods). - - -.. currentmodule:: logging - -.. class:: StreamHandler([stream]) - - Returns a new instance of the :class:`StreamHandler` class. If *stream* is - specified, the instance will use it for logging output; otherwise, *sys.stderr* - will be used. - - .. versionchanged:: 2.7 - The ``stream`` parameter was called ``strm`` in earlier versions. - - .. method:: emit(record) - - If a formatter is specified, it is used to format the record. The record - is then written to the stream with a trailing newline. If exception - information is present, it is formatted using - :func:`traceback.print_exception` and appended to the stream. - - - .. method:: flush() - - Flushes the stream by calling its :meth:`flush` method. Note that the - :meth:`close` method is inherited from :class:`Handler` and so does - no output, so an explicit :meth:`flush` call may be needed at times. - - -.. _file-handler: - -FileHandler -^^^^^^^^^^^ - -The :class:`FileHandler` class, located in the core :mod:`logging` package, -sends logging output to a disk file. It inherits the output functionality from -:class:`StreamHandler`. - - -.. class:: FileHandler(filename[, mode[, encoding[, delay]]]) - - Returns a new instance of the :class:`FileHandler` class. The specified file is - opened and used as the stream for logging. If *mode* is not specified, - :const:`'a'` is used. If *encoding* is not *None*, it is used to open the file - with that encoding. If *delay* is true, then file opening is deferred until the - first call to :meth:`emit`. By default, the file grows indefinitely. - - .. versionchanged:: 2.6 - *delay* was added. - - .. method:: close() - - Closes the file. - - - .. method:: emit(record) - - Outputs the record to the file. - - -.. _null-handler: - -NullHandler -^^^^^^^^^^^ - -.. versionadded:: 2.7 - -The :class:`NullHandler` class, located in the core :mod:`logging` package, -does not do any formatting or output. It is essentially a "no-op" handler -for use by library developers. - -.. class:: NullHandler() - - Returns a new instance of the :class:`NullHandler` class. - - .. method:: emit(record) - - This method does nothing. - - .. method:: handle(record) - - This method does nothing. - - .. method:: createLock() - - This method returns `None` for the lock, since there is no - underlying I/O to which access needs to be serialized. - - -See :ref:`library-config` for more information on how to use -:class:`NullHandler`. - -.. _watched-file-handler: - -WatchedFileHandler -^^^^^^^^^^^^^^^^^^ - -.. versionadded:: 2.6 - -.. currentmodule:: logging.handlers - -The :class:`WatchedFileHandler` class, located in the :mod:`logging.handlers` -module, is a :class:`FileHandler` which watches the file it is logging to. If -the file changes, it is closed and reopened using the file name. - -A file change can happen because of usage of programs such as *newsyslog* and -*logrotate* which perform log file rotation. This handler, intended for use -under Unix/Linux, watches the file to see if it has changed since the last emit. -(A file is deemed to have changed if its device or inode have changed.) If the -file has changed, the old file stream is closed, and the file opened to get a -new stream. - -This handler is not appropriate for use under Windows, because under Windows -open log files cannot be moved or renamed - logging opens the files with -exclusive locks - and so there is no need for such a handler. Furthermore, -*ST_INO* is not supported under Windows; :func:`stat` always returns zero for -this value. - - -.. class:: WatchedFileHandler(filename[,mode[, encoding[, delay]]]) - - Returns a new instance of the :class:`WatchedFileHandler` class. The specified - file is opened and used as the stream for logging. If *mode* is not specified, - :const:`'a'` is used. If *encoding* is not *None*, it is used to open the file - with that encoding. If *delay* is true, then file opening is deferred until the - first call to :meth:`emit`. By default, the file grows indefinitely. - - .. versionchanged:: 2.6 - *delay* was added. - - - .. method:: emit(record) - - Outputs the record to the file, but first checks to see if the file has - changed. If it has, the existing stream is flushed and closed and the - file opened again, before outputting the record to the file. - -.. _rotating-file-handler: - -RotatingFileHandler -^^^^^^^^^^^^^^^^^^^ - -The :class:`RotatingFileHandler` class, located in the :mod:`logging.handlers` -module, supports rotation of disk log files. - - -.. class:: RotatingFileHandler(filename[, mode[, maxBytes[, backupCount[, encoding[, delay]]]]]) - - Returns a new instance of the :class:`RotatingFileHandler` class. The specified - file is opened and used as the stream for logging. If *mode* is not specified, - ``'a'`` is used. If *encoding* is not *None*, it is used to open the file - with that encoding. If *delay* is true, then file opening is deferred until the - first call to :meth:`emit`. By default, the file grows indefinitely. - - You can use the *maxBytes* and *backupCount* values to allow the file to - :dfn:`rollover` at a predetermined size. When the size is about to be exceeded, - the file is closed and a new file is silently opened for output. Rollover occurs - whenever the current log file is nearly *maxBytes* in length; if *maxBytes* is - zero, rollover never occurs. If *backupCount* is non-zero, the system will save - old log files by appending the extensions ".1", ".2" etc., to the filename. For - example, with a *backupCount* of 5 and a base file name of :file:`app.log`, you - would get :file:`app.log`, :file:`app.log.1`, :file:`app.log.2`, up to - :file:`app.log.5`. The file being written to is always :file:`app.log`. When - this file is filled, it is closed and renamed to :file:`app.log.1`, and if files - :file:`app.log.1`, :file:`app.log.2`, etc. exist, then they are renamed to - :file:`app.log.2`, :file:`app.log.3` etc. respectively. - - .. versionchanged:: 2.6 - *delay* was added. - - .. method:: doRollover() - - Does a rollover, as described above. - - - .. method:: emit(record) - - Outputs the record to the file, catering for rollover as described - previously. - -.. _timed-rotating-file-handler: - -TimedRotatingFileHandler -^^^^^^^^^^^^^^^^^^^^^^^^ - -The :class:`TimedRotatingFileHandler` class, located in the -:mod:`logging.handlers` module, supports rotation of disk log files at certain -timed intervals. - - -.. class:: TimedRotatingFileHandler(filename [,when [,interval [,backupCount[, encoding[, delay[, utc]]]]]]) - - Returns a new instance of the :class:`TimedRotatingFileHandler` class. The - specified file is opened and used as the stream for logging. On rotating it also - sets the filename suffix. Rotating happens based on the product of *when* and - *interval*. - - You can use the *when* to specify the type of *interval*. The list of possible - values is below. Note that they are not case sensitive. - - +----------------+-----------------------+ - | Value | Type of interval | - +================+=======================+ - | ``'S'`` | Seconds | - +----------------+-----------------------+ - | ``'M'`` | Minutes | - +----------------+-----------------------+ - | ``'H'`` | Hours | - +----------------+-----------------------+ - | ``'D'`` | Days | - +----------------+-----------------------+ - | ``'W'`` | Week day (0=Monday) | - +----------------+-----------------------+ - | ``'midnight'`` | Roll over at midnight | - +----------------+-----------------------+ - - The system will save old log files by appending extensions to the filename. - The extensions are date-and-time based, using the strftime format - ``%Y-%m-%d_%H-%M-%S`` or a leading portion thereof, depending on the - rollover interval. - - When computing the next rollover time for the first time (when the handler - is created), the last modification time of an existing log file, or else - the current time, is used to compute when the next rotation will occur. - - If the *utc* argument is true, times in UTC will be used; otherwise - local time is used. - - If *backupCount* is nonzero, at most *backupCount* files - will be kept, and if more would be created when rollover occurs, the oldest - one is deleted. The deletion logic uses the interval to determine which - files to delete, so changing the interval may leave old files lying around. - - If *delay* is true, then file opening is deferred until the first call to - :meth:`emit`. - - .. versionchanged:: 2.6 - *delay* was added. - - .. method:: doRollover() - - Does a rollover, as described above. - - - .. method:: emit(record) - - Outputs the record to the file, catering for rollover as described above. - - -.. _socket-handler: - -SocketHandler -^^^^^^^^^^^^^ - -The :class:`SocketHandler` class, located in the :mod:`logging.handlers` module, -sends logging output to a network socket. The base class uses a TCP socket. - - -.. class:: SocketHandler(host, port) - - Returns a new instance of the :class:`SocketHandler` class intended to - communicate with a remote machine whose address is given by *host* and *port*. - - - .. method:: close() - - Closes the socket. - - - .. method:: emit() - - Pickles the record's attribute dictionary and writes it to the socket in - binary format. If there is an error with the socket, silently drops the - packet. If the connection was previously lost, re-establishes the - connection. To unpickle the record at the receiving end into a - :class:`LogRecord`, use the :func:`makeLogRecord` function. - - - .. method:: handleError() - - Handles an error which has occurred during :meth:`emit`. The most likely - cause is a lost connection. Closes the socket so that we can retry on the - next event. - - - .. method:: makeSocket() - - This is a factory method which allows subclasses to define the precise - type of socket they want. The default implementation creates a TCP socket - (:const:`socket.SOCK_STREAM`). - - - .. method:: makePickle(record) - - Pickles the record's attribute dictionary in binary format with a length - prefix, and returns it ready for transmission across the socket. - - Note that pickles aren't completely secure. If you are concerned about - security, you may want to override this method to implement a more secure - mechanism. For example, you can sign pickles using HMAC and then verify - them on the receiving end, or alternatively you can disable unpickling of - global objects on the receiving end. - - .. method:: send(packet) - - Send a pickled string *packet* to the socket. This function allows for - partial sends which can happen when the network is busy. - - -.. _datagram-handler: - -DatagramHandler -^^^^^^^^^^^^^^^ - -The :class:`DatagramHandler` class, located in the :mod:`logging.handlers` -module, inherits from :class:`SocketHandler` to support sending logging messages -over UDP sockets. - - -.. class:: DatagramHandler(host, port) - - Returns a new instance of the :class:`DatagramHandler` class intended to - communicate with a remote machine whose address is given by *host* and *port*. - - - .. method:: emit() - - Pickles the record's attribute dictionary and writes it to the socket in - binary format. If there is an error with the socket, silently drops the - packet. To unpickle the record at the receiving end into a - :class:`LogRecord`, use the :func:`makeLogRecord` function. - - - .. method:: makeSocket() - - The factory method of :class:`SocketHandler` is here overridden to create - a UDP socket (:const:`socket.SOCK_DGRAM`). - - - .. method:: send(s) - - Send a pickled string to a socket. - - -.. _syslog-handler: - -SysLogHandler -^^^^^^^^^^^^^ - -The :class:`SysLogHandler` class, located in the :mod:`logging.handlers` module, -supports sending logging messages to a remote or local Unix syslog. - - -.. class:: SysLogHandler([address[, facility[, socktype]]]) - - Returns a new instance of the :class:`SysLogHandler` class intended to - communicate with a remote Unix machine whose address is given by *address* in - the form of a ``(host, port)`` tuple. If *address* is not specified, - ``('localhost', 514)`` is used. The address is used to open a socket. An - alternative to providing a ``(host, port)`` tuple is providing an address as a - string, for example "/dev/log". In this case, a Unix domain socket is used to - send the message to the syslog. If *facility* is not specified, - :const:`LOG_USER` is used. The type of socket opened depends on the - *socktype* argument, which defaults to :const:`socket.SOCK_DGRAM` and thus - opens a UDP socket. To open a TCP socket (for use with the newer syslog - daemons such as rsyslog), specify a value of :const:`socket.SOCK_STREAM`. - - .. versionchanged:: 2.7 - *socktype* was added. - - - .. method:: close() - - Closes the socket to the remote host. - - - .. method:: emit(record) - - The record is formatted, and then sent to the syslog server. If exception - information is present, it is *not* sent to the server. - - - .. method:: encodePriority(facility, priority) - - Encodes the facility and priority into an integer. You can pass in strings - or integers - if strings are passed, internal mapping dictionaries are - used to convert them to integers. - - The symbolic ``LOG_`` values are defined in :class:`SysLogHandler` and - mirror the values defined in the ``sys/syslog.h`` header file. - - **Priorities** - - +--------------------------+---------------+ - | Name (string) | Symbolic value| - +==========================+===============+ - | ``alert`` | LOG_ALERT | - +--------------------------+---------------+ - | ``crit`` or ``critical`` | LOG_CRIT | - +--------------------------+---------------+ - | ``debug`` | LOG_DEBUG | - +--------------------------+---------------+ - | ``emerg`` or ``panic`` | LOG_EMERG | - +--------------------------+---------------+ - | ``err`` or ``error`` | LOG_ERR | - +--------------------------+---------------+ - | ``info`` | LOG_INFO | - +--------------------------+---------------+ - | ``notice`` | LOG_NOTICE | - +--------------------------+---------------+ - | ``warn`` or ``warning`` | LOG_WARNING | - +--------------------------+---------------+ - - **Facilities** - - +---------------+---------------+ - | Name (string) | Symbolic value| - +===============+===============+ - | ``auth`` | LOG_AUTH | - +---------------+---------------+ - | ``authpriv`` | LOG_AUTHPRIV | - +---------------+---------------+ - | ``cron`` | LOG_CRON | - +---------------+---------------+ - | ``daemon`` | LOG_DAEMON | - +---------------+---------------+ - | ``ftp`` | LOG_FTP | - +---------------+---------------+ - | ``kern`` | LOG_KERN | - +---------------+---------------+ - | ``lpr`` | LOG_LPR | - +---------------+---------------+ - | ``mail`` | LOG_MAIL | - +---------------+---------------+ - | ``news`` | LOG_NEWS | - +---------------+---------------+ - | ``syslog`` | LOG_SYSLOG | - +---------------+---------------+ - | ``user`` | LOG_USER | - +---------------+---------------+ - | ``uucp`` | LOG_UUCP | - +---------------+---------------+ - | ``local0`` | LOG_LOCAL0 | - +---------------+---------------+ - | ``local1`` | LOG_LOCAL1 | - +---------------+---------------+ - | ``local2`` | LOG_LOCAL2 | - +---------------+---------------+ - | ``local3`` | LOG_LOCAL3 | - +---------------+---------------+ - | ``local4`` | LOG_LOCAL4 | - +---------------+---------------+ - | ``local5`` | LOG_LOCAL5 | - +---------------+---------------+ - | ``local6`` | LOG_LOCAL6 | - +---------------+---------------+ - | ``local7`` | LOG_LOCAL7 | - +---------------+---------------+ - - .. method:: mapPriority(levelname) - - Maps a logging level name to a syslog priority name. - You may need to override this if you are using custom levels, or - if the default algorithm is not suitable for your needs. The - default algorithm maps ``DEBUG``, ``INFO``, ``WARNING``, ``ERROR`` and - ``CRITICAL`` to the equivalent syslog names, and all other level - names to "warning". - -.. _nt-eventlog-handler: - -NTEventLogHandler -^^^^^^^^^^^^^^^^^ - -The :class:`NTEventLogHandler` class, located in the :mod:`logging.handlers` -module, supports sending logging messages to a local Windows NT, Windows 2000 or -Windows XP event log. Before you can use it, you need Mark Hammond's Win32 -extensions for Python installed. - - -.. class:: NTEventLogHandler(appname[, dllname[, logtype]]) - - Returns a new instance of the :class:`NTEventLogHandler` class. The *appname* is - used to define the application name as it appears in the event log. An - appropriate registry entry is created using this name. The *dllname* should give - the fully qualified pathname of a .dll or .exe which contains message - definitions to hold in the log (if not specified, ``'win32service.pyd'`` is used - - this is installed with the Win32 extensions and contains some basic - placeholder message definitions. Note that use of these placeholders will make - your event logs big, as the entire message source is held in the log. If you - want slimmer logs, you have to pass in the name of your own .dll or .exe which - contains the message definitions you want to use in the event log). The - *logtype* is one of ``'Application'``, ``'System'`` or ``'Security'``, and - defaults to ``'Application'``. - - - .. method:: close() - - At this point, you can remove the application name from the registry as a - source of event log entries. However, if you do this, you will not be able - to see the events as you intended in the Event Log Viewer - it needs to be - able to access the registry to get the .dll name. The current version does - not do this. - - - .. method:: emit(record) - - Determines the message ID, event category and event type, and then logs - the message in the NT event log. - - - .. method:: getEventCategory(record) - - Returns the event category for the record. Override this if you want to - specify your own categories. This version returns 0. - - - .. method:: getEventType(record) - - Returns the event type for the record. Override this if you want to - specify your own types. This version does a mapping using the handler's - typemap attribute, which is set up in :meth:`__init__` to a dictionary - which contains mappings for :const:`DEBUG`, :const:`INFO`, - :const:`WARNING`, :const:`ERROR` and :const:`CRITICAL`. If you are using - your own levels, you will either need to override this method or place a - suitable dictionary in the handler's *typemap* attribute. - - - .. method:: getMessageID(record) - - Returns the message ID for the record. If you are using your own messages, - you could do this by having the *msg* passed to the logger being an ID - rather than a format string. Then, in here, you could use a dictionary - lookup to get the message ID. This version returns 1, which is the base - message ID in :file:`win32service.pyd`. - -.. _smtp-handler: - -SMTPHandler -^^^^^^^^^^^ - -The :class:`SMTPHandler` class, located in the :mod:`logging.handlers` module, -supports sending logging messages to an email address via SMTP. - - -.. class:: SMTPHandler(mailhost, fromaddr, toaddrs, subject[, credentials]) - - Returns a new instance of the :class:`SMTPHandler` class. The instance is - initialized with the from and to addresses and subject line of the email. The - *toaddrs* should be a list of strings. To specify a non-standard SMTP port, use - the (host, port) tuple format for the *mailhost* argument. If you use a string, - the standard SMTP port is used. If your SMTP server requires authentication, you - can specify a (username, password) tuple for the *credentials* argument. - - .. versionchanged:: 2.6 - *credentials* was added. - - - .. method:: emit(record) - - Formats the record and sends it to the specified addressees. - - - .. method:: getSubject(record) - - If you want to specify a subject line which is record-dependent, override - this method. - -.. _memory-handler: - -MemoryHandler -^^^^^^^^^^^^^ - -The :class:`MemoryHandler` class, located in the :mod:`logging.handlers` module, -supports buffering of logging records in memory, periodically flushing them to a -:dfn:`target` handler. Flushing occurs whenever the buffer is full, or when an -event of a certain severity or greater is seen. - -:class:`MemoryHandler` is a subclass of the more general -:class:`BufferingHandler`, which is an abstract class. This buffers logging -records in memory. Whenever each record is added to the buffer, a check is made -by calling :meth:`shouldFlush` to see if the buffer should be flushed. If it -should, then :meth:`flush` is expected to do the needful. - - -.. class:: BufferingHandler(capacity) - - Initializes the handler with a buffer of the specified capacity. - - - .. method:: emit(record) - - Appends the record to the buffer. If :meth:`shouldFlush` returns true, - calls :meth:`flush` to process the buffer. - - - .. method:: flush() - - You can override this to implement custom flushing behavior. This version - just zaps the buffer to empty. - - - .. method:: shouldFlush(record) - - Returns true if the buffer is up to capacity. This method can be - overridden to implement custom flushing strategies. - - -.. class:: MemoryHandler(capacity[, flushLevel [, target]]) - - Returns a new instance of the :class:`MemoryHandler` class. The instance is - initialized with a buffer size of *capacity*. If *flushLevel* is not specified, - :const:`ERROR` is used. If no *target* is specified, the target will need to be - set using :meth:`setTarget` before this handler does anything useful. - - - .. method:: close() - - Calls :meth:`flush`, sets the target to :const:`None` and clears the - buffer. - - - .. method:: flush() - - For a :class:`MemoryHandler`, flushing means just sending the buffered - records to the target, if there is one. Override if you want different - behavior. - - - .. method:: setTarget(target) - - Sets the target handler for this handler. - - - .. method:: shouldFlush(record) - - Checks for buffer full or a record at the *flushLevel* or higher. - - -.. _http-handler: - -HTTPHandler -^^^^^^^^^^^ - -The :class:`HTTPHandler` class, located in the :mod:`logging.handlers` module, -supports sending logging messages to a Web server, using either ``GET`` or -``POST`` semantics. - - -.. class:: HTTPHandler(host, url[, method]) - - Returns a new instance of the :class:`HTTPHandler` class. The instance is - initialized with a host address, url and HTTP method. The *host* can be of the - form ``host:port``, should you need to use a specific port number. If no - *method* is specified, ``GET`` is used. - - - .. method:: emit(record) - - Sends the record to the Web server as a percent-encoded dictionary. - - -.. _formatter: - -Formatter Objects ------------------ - -.. currentmodule:: logging - -:class:`Formatter`\ s have the following attributes and methods. They are -responsible for converting a :class:`LogRecord` to (usually) a string which can -be interpreted by either a human or an external system. The base -:class:`Formatter` allows a formatting string to be specified. If none is -supplied, the default value of ``'%(message)s'`` is used. - -A Formatter can be initialized with a format string which makes use of knowledge -of the :class:`LogRecord` attributes - such as the default value mentioned above -making use of the fact that the user's message and arguments are pre-formatted -into a :class:`LogRecord`'s *message* attribute. This format string contains -standard Python %-style mapping keys. See section :ref:`string-formatting` -for more information on string formatting. - -Currently, the useful mapping keys in a :class:`LogRecord` are: - -+-------------------------+-----------------------------------------------+ -| Format | Description | -+=========================+===============================================+ -| ``%(name)s`` | Name of the logger (logging channel). | -+-------------------------+-----------------------------------------------+ -| ``%(levelno)s`` | Numeric logging level for the message | -| | (:const:`DEBUG`, :const:`INFO`, | -| | :const:`WARNING`, :const:`ERROR`, | -| | :const:`CRITICAL`). | -+-------------------------+-----------------------------------------------+ -| ``%(levelname)s`` | Text logging level for the message | -| | (``'DEBUG'``, ``'INFO'``, ``'WARNING'``, | -| | ``'ERROR'``, ``'CRITICAL'``). | -+-------------------------+-----------------------------------------------+ -| ``%(pathname)s`` | Full pathname of the source file where the | -| | logging call was issued (if available). | -+-------------------------+-----------------------------------------------+ -| ``%(filename)s`` | Filename portion of pathname. | -+-------------------------+-----------------------------------------------+ -| ``%(module)s`` | Module (name portion of filename). | -+-------------------------+-----------------------------------------------+ -| ``%(funcName)s`` | Name of function containing the logging call. | -+-------------------------+-----------------------------------------------+ -| ``%(lineno)d`` | Source line number where the logging call was | -| | issued (if available). | -+-------------------------+-----------------------------------------------+ -| ``%(created)f`` | Time when the :class:`LogRecord` was created | -| | (as returned by :func:`time.time`). | -+-------------------------+-----------------------------------------------+ -| ``%(relativeCreated)d`` | Time in milliseconds when the LogRecord was | -| | created, relative to the time the logging | -| | module was loaded. | -+-------------------------+-----------------------------------------------+ -| ``%(asctime)s`` | Human-readable time when the | -| | :class:`LogRecord` was created. By default | -| | this is of the form "2003-07-08 16:49:45,896" | -| | (the numbers after the comma are millisecond | -| | portion of the time). | -+-------------------------+-----------------------------------------------+ -| ``%(msecs)d`` | Millisecond portion of the time when the | -| | :class:`LogRecord` was created. | -+-------------------------+-----------------------------------------------+ -| ``%(thread)d`` | Thread ID (if available). | -+-------------------------+-----------------------------------------------+ -| ``%(threadName)s`` | Thread name (if available). | -+-------------------------+-----------------------------------------------+ -| ``%(process)d`` | Process ID (if available). | -+-------------------------+-----------------------------------------------+ -| ``%(processName)s`` | Process name (if available). | -+-------------------------+-----------------------------------------------+ -| ``%(message)s`` | The logged message, computed as ``msg % | -| | args``. | -+-------------------------+-----------------------------------------------+ - -.. versionchanged:: 2.5 - *funcName* was added. - -.. versionchanged:: 2.6 - *processName* was added. - - -.. class:: Formatter([fmt[, datefmt]]) - - Returns a new instance of the :class:`Formatter` class. The instance is - initialized with a format string for the message as a whole, as well as a - format string for the date/time portion of a message. If no *fmt* is - specified, ``'%(message)s'`` is used. If no *datefmt* is specified, the - ISO8601 date format is used. - - .. method:: format(record) - - The record's attribute dictionary is used as the operand to a string - formatting operation. Returns the resulting string. Before formatting the - dictionary, a couple of preparatory steps are carried out. The *message* - attribute of the record is computed using *msg* % *args*. If the - formatting string contains ``'(asctime)'``, :meth:`formatTime` is called - to format the event time. If there is exception information, it is - formatted using :meth:`formatException` and appended to the message. Note - that the formatted exception information is cached in attribute - *exc_text*. This is useful because the exception information can be - pickled and sent across the wire, but you should be careful if you have - more than one :class:`Formatter` subclass which customizes the formatting - of exception information. In this case, you will have to clear the cached - value after a formatter has done its formatting, so that the next - formatter to handle the event doesn't use the cached value but - recalculates it afresh. - - - .. method:: formatTime(record[, datefmt]) - - This method should be called from :meth:`format` by a formatter which - wants to make use of a formatted time. This method can be overridden in - formatters to provide for any specific requirement, but the basic behavior - is as follows: if *datefmt* (a string) is specified, it is used with - :func:`time.strftime` to format the creation time of the - record. Otherwise, the ISO8601 format is used. The resulting string is - returned. - - - .. method:: formatException(exc_info) - - Formats the specified exception information (a standard exception tuple as - returned by :func:`sys.exc_info`) as a string. This default implementation - just uses :func:`traceback.print_exception`. The resulting string is - returned. - -.. _filter: - -Filter Objects --------------- - -:class:`Filter`\ s can be used by :class:`Handler`\ s and :class:`Logger`\ s for -more sophisticated filtering than is provided by levels. The base filter class -only allows events which are below a certain point in the logger hierarchy. For -example, a filter initialized with "A.B" will allow events logged by loggers -"A.B", "A.B.C", "A.B.C.D", "A.B.D" etc. but not "A.BB", "B.A.B" etc. If -initialized with the empty string, all events are passed. - - -.. class:: Filter([name]) - - Returns an instance of the :class:`Filter` class. If *name* is specified, it - names a logger which, together with its children, will have its events allowed - through the filter. If *name* is the empty string, allows every event. - - - .. method:: filter(record) - - Is the specified record to be logged? Returns zero for no, nonzero for - yes. If deemed appropriate, the record may be modified in-place by this - method. - -Note that filters attached to handlers are consulted whenever an event is -emitted by the handler, whereas filters attached to loggers are consulted -whenever an event is logged to the handler (using :meth:`debug`, :meth:`info`, -etc.) This means that events which have been generated by descendant loggers -will not be filtered by a logger's filter setting, unless the filter has also -been applied to those descendant loggers. - -You don't actually need to subclass ``Filter``: you can pass any instance -which has a ``filter`` method with the same semantics. - -Other uses for filters -^^^^^^^^^^^^^^^^^^^^^^ - -Although filters are used primarily to filter records based on more -sophisticated criteria than levels, they get to see every record which is -processed by the handler or logger they're attached to: this can be useful if -you want to do things like counting how many records were processed by a -particular logger or handler, or adding, changing or removing attributes in -the LogRecord being processed. Obviously changing the LogRecord needs to be -done with some care, but it does allow the injection of contextual information -into logs (see :ref:`filters-contextual`). - -.. _log-record: - -LogRecord Objects ------------------ - -:class:`LogRecord` instances are created automatically by the :class:`Logger` -every time something is logged, and can be created manually via -:func:`makeLogRecord` (for example, from a pickled event received over the -wire). - - -.. class:: - LogRecord(name, lvl, pathname, lineno, msg, args, exc_info [, func=None]) - - Contains all the information pertinent to the event being logged. - - The primary information is passed in :attr:`msg` and :attr:`args`, which - are combined using ``msg % args`` to create the :attr:`message` field of the - record. - - .. attribute:: args - - Tuple of arguments to be used in formatting :attr:`msg`. - - .. attribute:: exc_info - - Exception tuple (? la `sys.exc_info`) or `None` if no exception - information is available. - - .. attribute:: func - - Name of the function of origin (i.e. in which the logging call was made). - - .. attribute:: lineno - - Line number in the source file of origin. - - .. attribute:: lvl - - Numeric logging level. - - .. attribute:: message - - Bound to the result of :meth:`getMessage` when - :meth:`Formatter.format(record)` is invoked. - - .. attribute:: msg - - User-supplied :ref:`format string` or arbitrary object - (see :ref:`arbitrary-object-messages`) used in :meth:`getMessage`. - - .. attribute:: name - - Name of the logger that emitted the record. - - .. attribute:: pathname - - Absolute pathname of the source file of origin. - - .. method:: getMessage() - - Returns the message for this :class:`LogRecord` instance after merging any - user-supplied arguments with the message. If the user-supplied message - argument to the logging call is not a string, :func:`str` is called on it to - convert it to a string. This allows use of user-defined classes as - messages, whose ``__str__`` method can return the actual format string to - be used. - - .. versionchanged:: 2.5 - *func* was added. - - -.. _logger-adapter: - -LoggerAdapter Objects ---------------------- - -.. versionadded:: 2.6 - -:class:`LoggerAdapter` instances are used to conveniently pass contextual -information into logging calls. For a usage example , see the section on -:ref:`adding contextual information to your logging output `. - - -.. class:: LoggerAdapter(logger, extra) - - Returns an instance of :class:`LoggerAdapter` initialized with an - underlying :class:`Logger` instance and a dict-like object. - - .. method:: process(msg, kwargs) - - Modifies the message and/or keyword arguments passed to a logging call in - order to insert contextual information. This implementation takes the object - passed as *extra* to the constructor and adds it to *kwargs* using key - 'extra'. The return value is a (*msg*, *kwargs*) tuple which has the - (possibly modified) versions of the arguments passed in. - -In addition to the above, :class:`LoggerAdapter` supports all the logging -methods of :class:`Logger`, i.e. :meth:`debug`, :meth:`info`, :meth:`warning`, -:meth:`error`, :meth:`exception`, :meth:`critical` and :meth:`log`. These -methods have the same signatures as their counterparts in :class:`Logger`, so -you can use the two types of instances interchangeably. - -.. versionchanged:: 2.7 - -The :meth:`isEnabledFor` method was added to :class:`LoggerAdapter`. This method -delegates to the underlying logger. - - -Thread Safety -------------- - -The logging module is intended to be thread-safe without any special work -needing to be done by its clients. It achieves this though using threading -locks; there is one lock to serialize access to the module's shared data, and -each handler also creates a lock to serialize access to its underlying I/O. - -If you are implementing asynchronous signal handlers using the :mod:`signal` -module, you may not be able to use logging from within such handlers. This is -because lock implementations in the :mod:`threading` module are not always -re-entrant, and so cannot be invoked from such signal handlers. - - -Integration with the warnings module ------------------------------------- - -The :func:`captureWarnings` function can be used to integrate :mod:`logging` -with the :mod:`warnings` module. - -.. function:: captureWarnings(capture) - - This function is used to turn the capture of warnings by logging on and - off. - - If *capture* is ``True``, warnings issued by the :mod:`warnings` module - will be redirected to the logging system. Specifically, a warning will be - formatted using :func:`warnings.formatwarning` and the resulting string - logged to a logger named "py.warnings" with a severity of ``WARNING``. - - If *capture* is ``False``, the redirection of warnings to the logging system - will stop, and warnings will be redirected to their original destinations - (i.e. those in effect before ``captureWarnings(True)`` was called). - - -Configuration -------------- - - -.. _logging-config-api: - -Configuration functions -^^^^^^^^^^^^^^^^^^^^^^^ - -The following functions configure the logging module. They are located in the -:mod:`logging.config` module. Their use is optional --- you can configure the -logging module using these functions or by making calls to the main API (defined -in :mod:`logging` itself) and defining handlers which are declared either in -:mod:`logging` or :mod:`logging.handlers`. - -.. currentmodule:: logging.config - -.. function:: dictConfig(config) - - Takes the logging configuration from a dictionary. The contents of - this dictionary are described in :ref:`logging-config-dictschema` - below. - - If an error is encountered during configuration, this function will - raise a :exc:`ValueError`, :exc:`TypeError`, :exc:`AttributeError` - or :exc:`ImportError` with a suitably descriptive message. The - following is a (possibly incomplete) list of conditions which will - raise an error: - - * A ``level`` which is not a string or which is a string not - corresponding to an actual logging level. - * A ``propagate`` value which is not a boolean. - * An id which does not have a corresponding destination. - * A non-existent handler id found during an incremental call. - * An invalid logger name. - * Inability to resolve to an internal or external object. - - Parsing is performed by the :class:`DictConfigurator` class, whose - constructor is passed the dictionary used for configuration, and - has a :meth:`configure` method. The :mod:`logging.config` module - has a callable attribute :attr:`dictConfigClass` - which is initially set to :class:`DictConfigurator`. - You can replace the value of :attr:`dictConfigClass` with a - suitable implementation of your own. - - :func:`dictConfig` calls :attr:`dictConfigClass` passing - the specified dictionary, and then calls the :meth:`configure` method on - the returned object to put the configuration into effect:: - - def dictConfig(config): - dictConfigClass(config).configure() - - For example, a subclass of :class:`DictConfigurator` could call - ``DictConfigurator.__init__()`` in its own :meth:`__init__()`, then - set up custom prefixes which would be usable in the subsequent - :meth:`configure` call. :attr:`dictConfigClass` would be bound to - this new subclass, and then :func:`dictConfig` could be called exactly as - in the default, uncustomized state. - - .. versionadded:: 2.7 - -.. function:: fileConfig(fname[, defaults]) - - Reads the logging configuration from a :mod:`ConfigParser`\-format file named - *fname*. This function can be called several times from an application, - allowing an end user to select from various pre-canned - configurations (if the developer provides a mechanism to present the choices - and load the chosen configuration). Defaults to be passed to the ConfigParser - can be specified in the *defaults* argument. - -.. function:: listen([port]) - - Starts up a socket server on the specified port, and listens for new - configurations. If no port is specified, the module's default - :const:`DEFAULT_LOGGING_CONFIG_PORT` is used. Logging configurations will be - sent as a file suitable for processing by :func:`fileConfig`. Returns a - :class:`Thread` instance on which you can call :meth:`start` to start the - server, and which you can :meth:`join` when appropriate. To stop the server, - call :func:`stopListening`. - - To send a configuration to the socket, read in the configuration file and - send it to the socket as a string of bytes preceded by a four-byte length - string packed in binary using ``struct.pack('>L', n)``. - - -.. function:: stopListening() - - Stops the listening server which was created with a call to :func:`listen`. - This is typically called before calling :meth:`join` on the return value from - :func:`listen`. - -.. currentmodule:: logging - -.. _logging-config-dictschema: - -Configuration dictionary schema -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Describing a logging configuration requires listing the various -objects to create and the connections between them; for example, you -may create a handler named "console" and then say that the logger -named "startup" will send its messages to the "console" handler. -These objects aren't limited to those provided by the :mod:`logging` -module because you might write your own formatter or handler class. -The parameters to these classes may also need to include external -objects such as ``sys.stderr``. The syntax for describing these -objects and connections is defined in :ref:`logging-config-dict-connections` -below. - -Dictionary Schema Details -""""""""""""""""""""""""" - -The dictionary passed to :func:`dictConfig` must contain the following -keys: - -* `version` - to be set to an integer value representing the schema - version. The only valid value at present is 1, but having this key - allows the schema to evolve while still preserving backwards - compatibility. - -All other keys are optional, but if present they will be interpreted -as described below. In all cases below where a 'configuring dict' is -mentioned, it will be checked for the special ``'()'`` key to see if a -custom instantiation is required. If so, the mechanism described in -:ref:`logging-config-dict-userdef` below is used to create an instance; -otherwise, the context is used to determine what to instantiate. - -* `formatters` - the corresponding value will be a dict in which each - key is a formatter id and each value is a dict describing how to - configure the corresponding Formatter instance. - - The configuring dict is searched for keys ``format`` and ``datefmt`` - (with defaults of ``None``) and these are used to construct a - :class:`logging.Formatter` instance. - -* `filters` - the corresponding value will be a dict in which each key - is a filter id and each value is a dict describing how to configure - the corresponding Filter instance. - - The configuring dict is searched for the key ``name`` (defaulting to the - empty string) and this is used to construct a :class:`logging.Filter` - instance. - -* `handlers` - the corresponding value will be a dict in which each - key is a handler id and each value is a dict describing how to - configure the corresponding Handler instance. - - The configuring dict is searched for the following keys: - - * ``class`` (mandatory). This is the fully qualified name of the - handler class. - - * ``level`` (optional). The level of the handler. - - * ``formatter`` (optional). The id of the formatter for this - handler. - - * ``filters`` (optional). A list of ids of the filters for this - handler. - - All *other* keys are passed through as keyword arguments to the - handler's constructor. For example, given the snippet:: - - handlers: - console: - class : logging.StreamHandler - formatter: brief - level : INFO - filters: [allow_foo] - stream : ext://sys.stdout - file: - class : logging.handlers.RotatingFileHandler - formatter: precise - filename: logconfig.log - maxBytes: 1024 - backupCount: 3 - - the handler with id ``console`` is instantiated as a - :class:`logging.StreamHandler`, using ``sys.stdout`` as the underlying - stream. The handler with id ``file`` is instantiated as a - :class:`logging.handlers.RotatingFileHandler` with the keyword arguments - ``filename='logconfig.log', maxBytes=1024, backupCount=3``. - -* `loggers` - the corresponding value will be a dict in which each key - is a logger name and each value is a dict describing how to - configure the corresponding Logger instance. - - The configuring dict is searched for the following keys: - - * ``level`` (optional). The level of the logger. - - * ``propagate`` (optional). The propagation setting of the logger. - - * ``filters`` (optional). A list of ids of the filters for this - logger. - - * ``handlers`` (optional). A list of ids of the handlers for this - logger. - - The specified loggers will be configured according to the level, - propagation, filters and handlers specified. - -* `root` - this will be the configuration for the root logger. - Processing of the configuration will be as for any logger, except - that the ``propagate`` setting will not be applicable. - -* `incremental` - whether the configuration is to be interpreted as - incremental to the existing configuration. This value defaults to - ``False``, which means that the specified configuration replaces the - existing configuration with the same semantics as used by the - existing :func:`fileConfig` API. - - If the specified value is ``True``, the configuration is processed - as described in the section on :ref:`logging-config-dict-incremental`. - -* `disable_existing_loggers` - whether any existing loggers are to be - disabled. This setting mirrors the parameter of the same name in - :func:`fileConfig`. If absent, this parameter defaults to ``True``. - This value is ignored if `incremental` is ``True``. - -.. _logging-config-dict-incremental: - -Incremental Configuration -""""""""""""""""""""""""" - -It is difficult to provide complete flexibility for incremental -configuration. For example, because objects such as filters -and formatters are anonymous, once a configuration is set up, it is -not possible to refer to such anonymous objects when augmenting a -configuration. - -Furthermore, there is not a compelling case for arbitrarily altering -the object graph of loggers, handlers, filters, formatters at -run-time, once a configuration is set up; the verbosity of loggers and -handlers can be controlled just by setting levels (and, in the case of -loggers, propagation flags). Changing the object graph arbitrarily in -a safe way is problematic in a multi-threaded environment; while not -impossible, the benefits are not worth the complexity it adds to the -implementation. - -Thus, when the ``incremental`` key of a configuration dict is present -and is ``True``, the system will completely ignore any ``formatters`` and -``filters`` entries, and process only the ``level`` -settings in the ``handlers`` entries, and the ``level`` and -``propagate`` settings in the ``loggers`` and ``root`` entries. - -Using a value in the configuration dict lets configurations to be sent -over the wire as pickled dicts to a socket listener. Thus, the logging -verbosity of a long-running application can be altered over time with -no need to stop and restart the application. - -.. _logging-config-dict-connections: - -Object connections -"""""""""""""""""" - -The schema describes a set of logging objects - loggers, -handlers, formatters, filters - which are connected to each other in -an object graph. Thus, the schema needs to represent connections -between the objects. For example, say that, once configured, a -particular logger has attached to it a particular handler. For the -purposes of this discussion, we can say that the logger represents the -source, and the handler the destination, of a connection between the -two. Of course in the configured objects this is represented by the -logger holding a reference to the handler. In the configuration dict, -this is done by giving each destination object an id which identifies -it unambiguously, and then using the id in the source object's -configuration to indicate that a connection exists between the source -and the destination object with that id. - -So, for example, consider the following YAML snippet:: - - formatters: - brief: - # configuration for formatter with id 'brief' goes here - precise: - # configuration for formatter with id 'precise' goes here - handlers: - h1: #This is an id - # configuration of handler with id 'h1' goes here - formatter: brief - h2: #This is another id - # configuration of handler with id 'h2' goes here - formatter: precise - loggers: - foo.bar.baz: - # other configuration for logger 'foo.bar.baz' - handlers: [h1, h2] - -(Note: YAML used here because it's a little more readable than the -equivalent Python source form for the dictionary.) - -The ids for loggers are the logger names which would be used -programmatically to obtain a reference to those loggers, e.g. -``foo.bar.baz``. The ids for Formatters and Filters can be any string -value (such as ``brief``, ``precise`` above) and they are transient, -in that they are only meaningful for processing the configuration -dictionary and used to determine connections between objects, and are -not persisted anywhere when the configuration call is complete. - -The above snippet indicates that logger named ``foo.bar.baz`` should -have two handlers attached to it, which are described by the handler -ids ``h1`` and ``h2``. The formatter for ``h1`` is that described by id -``brief``, and the formatter for ``h2`` is that described by id -``precise``. - - -.. _logging-config-dict-userdef: - -User-defined objects -"""""""""""""""""""" - -The schema supports user-defined objects for handlers, filters and -formatters. (Loggers do not need to have different types for -different instances, so there is no support in this configuration -schema for user-defined logger classes.) - -Objects to be configured are described by dictionaries -which detail their configuration. In some places, the logging system -will be able to infer from the context how an object is to be -instantiated, but when a user-defined object is to be instantiated, -the system will not know how to do this. In order to provide complete -flexibility for user-defined object instantiation, the user needs -to provide a 'factory' - a callable which is called with a -configuration dictionary and which returns the instantiated object. -This is signalled by an absolute import path to the factory being -made available under the special key ``'()'``. Here's a concrete -example:: - - formatters: - brief: - format: '%(message)s' - default: - format: '%(asctime)s %(levelname)-8s %(name)-15s %(message)s' - datefmt: '%Y-%m-%d %H:%M:%S' - custom: - (): my.package.customFormatterFactory - bar: baz - spam: 99.9 - answer: 42 - -The above YAML snippet defines three formatters. The first, with id -``brief``, is a standard :class:`logging.Formatter` instance with the -specified format string. The second, with id ``default``, has a -longer format and also defines the time format explicitly, and will -result in a :class:`logging.Formatter` initialized with those two format -strings. Shown in Python source form, the ``brief`` and ``default`` -formatters have configuration sub-dictionaries:: - - { - 'format' : '%(message)s' - } - -and:: - - { - 'format' : '%(asctime)s %(levelname)-8s %(name)-15s %(message)s', - 'datefmt' : '%Y-%m-%d %H:%M:%S' - } - -respectively, and as these dictionaries do not contain the special key -``'()'``, the instantiation is inferred from the context: as a result, -standard :class:`logging.Formatter` instances are created. The -configuration sub-dictionary for the third formatter, with id -``custom``, is:: - - { - '()' : 'my.package.customFormatterFactory', - 'bar' : 'baz', - 'spam' : 99.9, - 'answer' : 42 - } - -and this contains the special key ``'()'``, which means that -user-defined instantiation is wanted. In this case, the specified -factory callable will be used. If it is an actual callable it will be -used directly - otherwise, if you specify a string (as in the example) -the actual callable will be located using normal import mechanisms. -The callable will be called with the **remaining** items in the -configuration sub-dictionary as keyword arguments. In the above -example, the formatter with id ``custom`` will be assumed to be -returned by the call:: - - my.package.customFormatterFactory(bar='baz', spam=99.9, answer=42) - -The key ``'()'`` has been used as the special key because it is not a -valid keyword parameter name, and so will not clash with the names of -the keyword arguments used in the call. The ``'()'`` also serves as a -mnemonic that the corresponding value is a callable. - - -.. _logging-config-dict-externalobj: - -Access to external objects -"""""""""""""""""""""""""" - -There are times where a configuration needs to refer to objects -external to the configuration, for example ``sys.stderr``. If the -configuration dict is constructed using Python code, this is -straightforward, but a problem arises when the configuration is -provided via a text file (e.g. JSON, YAML). In a text file, there is -no standard way to distinguish ``sys.stderr`` from the literal string -``'sys.stderr'``. To facilitate this distinction, the configuration -system looks for certain special prefixes in string values and -treat them specially. For example, if the literal string -``'ext://sys.stderr'`` is provided as a value in the configuration, -then the ``ext://`` will be stripped off and the remainder of the -value processed using normal import mechanisms. - -The handling of such prefixes is done in a way analogous to protocol -handling: there is a generic mechanism to look for prefixes which -match the regular expression ``^(?P[a-z]+)://(?P.*)$`` -whereby, if the ``prefix`` is recognised, the ``suffix`` is processed -in a prefix-dependent manner and the result of the processing replaces -the string value. If the prefix is not recognised, then the string -value will be left as-is. - - -.. _logging-config-dict-internalobj: - -Access to internal objects -"""""""""""""""""""""""""" - -As well as external objects, there is sometimes also a need to refer -to objects in the configuration. This will be done implicitly by the -configuration system for things that it knows about. For example, the -string value ``'DEBUG'`` for a ``level`` in a logger or handler will -automatically be converted to the value ``logging.DEBUG``, and the -``handlers``, ``filters`` and ``formatter`` entries will take an -object id and resolve to the appropriate destination object. - -However, a more generic mechanism is needed for user-defined -objects which are not known to the :mod:`logging` module. For -example, consider :class:`logging.handlers.MemoryHandler`, which takes -a ``target`` argument which is another handler to delegate to. Since -the system already knows about this class, then in the configuration, -the given ``target`` just needs to be the object id of the relevant -target handler, and the system will resolve to the handler from the -id. If, however, a user defines a ``my.package.MyHandler`` which has -an ``alternate`` handler, the configuration system would not know that -the ``alternate`` referred to a handler. To cater for this, a generic -resolution system allows the user to specify:: - - handlers: - file: - # configuration of file handler goes here - - custom: - (): my.package.MyHandler - alternate: cfg://handlers.file - -The literal string ``'cfg://handlers.file'`` will be resolved in an -analogous way to strings with the ``ext://`` prefix, but looking -in the configuration itself rather than the import namespace. The -mechanism allows access by dot or by index, in a similar way to -that provided by ``str.format``. Thus, given the following snippet:: - - handlers: - email: - class: logging.handlers.SMTPHandler - mailhost: localhost - fromaddr: my_app at domain.tld - toaddrs: - - support_team at domain.tld - - dev_team at domain.tld - subject: Houston, we have a problem. - -in the configuration, the string ``'cfg://handlers'`` would resolve to -the dict with key ``handlers``, the string ``'cfg://handlers.email`` -would resolve to the dict with key ``email`` in the ``handlers`` dict, -and so on. The string ``'cfg://handlers.email.toaddrs[1]`` would -resolve to ``'dev_team.domain.tld'`` and the string -``'cfg://handlers.email.toaddrs[0]'`` would resolve to the value -``'support_team at domain.tld'``. The ``subject`` value could be accessed -using either ``'cfg://handlers.email.subject'`` or, equivalently, -``'cfg://handlers.email[subject]'``. The latter form only needs to be -used if the key contains spaces or non-alphanumeric characters. If an -index value consists only of decimal digits, access will be attempted -using the corresponding integer value, falling back to the string -value if needed. - -Given a string ``cfg://handlers.myhandler.mykey.123``, this will -resolve to ``config_dict['handlers']['myhandler']['mykey']['123']``. -If the string is specified as ``cfg://handlers.myhandler.mykey[123]``, -the system will attempt to retrieve the value from -``config_dict['handlers']['myhandler']['mykey'][123]``, and fall back -to ``config_dict['handlers']['myhandler']['mykey']['123']`` if that -fails. - -.. _logging-config-fileformat: - -Configuration file format -^^^^^^^^^^^^^^^^^^^^^^^^^ - -The configuration file format understood by :func:`fileConfig` is based on -:mod:`ConfigParser` functionality. The file must contain sections called -``[loggers]``, ``[handlers]`` and ``[formatters]`` which identify by name the -entities of each type which are defined in the file. For each such entity, -there is a separate section which identifies how that entity is configured. -Thus, for a logger named ``log01`` in the ``[loggers]`` section, the relevant -configuration details are held in a section ``[logger_log01]``. Similarly, a -handler called ``hand01`` in the ``[handlers]`` section will have its -configuration held in a section called ``[handler_hand01]``, while a formatter -called ``form01`` in the ``[formatters]`` section will have its configuration -specified in a section called ``[formatter_form01]``. The root logger -configuration must be specified in a section called ``[logger_root]``. - -Examples of these sections in the file are given below. :: - - [loggers] - keys=root,log02,log03,log04,log05,log06,log07 - - [handlers] - keys=hand01,hand02,hand03,hand04,hand05,hand06,hand07,hand08,hand09 - - [formatters] - keys=form01,form02,form03,form04,form05,form06,form07,form08,form09 - -The root logger must specify a level and a list of handlers. An example of a -root logger section is given below. :: - - [logger_root] - level=NOTSET - handlers=hand01 - -The ``level`` entry can be one of ``DEBUG, INFO, WARNING, ERROR, CRITICAL`` or -``NOTSET``. For the root logger only, ``NOTSET`` means that all messages will be -logged. Level values are :func:`eval`\ uated in the context of the ``logging`` -package's namespace. - -The ``handlers`` entry is a comma-separated list of handler names, which must -appear in the ``[handlers]`` section. These names must appear in the -``[handlers]`` section and have corresponding sections in the configuration -file. - -For loggers other than the root logger, some additional information is required. -This is illustrated by the following example. :: - - [logger_parser] - level=DEBUG - handlers=hand01 - propagate=1 - qualname=compiler.parser - -The ``level`` and ``handlers`` entries are interpreted as for the root logger, -except that if a non-root logger's level is specified as ``NOTSET``, the system -consults loggers higher up the hierarchy to determine the effective level of the -logger. The ``propagate`` entry is set to 1 to indicate that messages must -propagate to handlers higher up the logger hierarchy from this logger, or 0 to -indicate that messages are **not** propagated to handlers up the hierarchy. The -``qualname`` entry is the hierarchical channel name of the logger, that is to -say the name used by the application to get the logger. - -Sections which specify handler configuration are exemplified by the following. -:: - - [handler_hand01] - class=StreamHandler - level=NOTSET - formatter=form01 - args=(sys.stdout,) - -The ``class`` entry indicates the handler's class (as determined by :func:`eval` -in the ``logging`` package's namespace). The ``level`` is interpreted as for -loggers, and ``NOTSET`` is taken to mean "log everything". - -.. versionchanged:: 2.6 - Added support for resolving the handler's class as a dotted module and class - name. - -The ``formatter`` entry indicates the key name of the formatter for this -handler. If blank, a default formatter (``logging._defaultFormatter``) is used. -If a name is specified, it must appear in the ``[formatters]`` section and have -a corresponding section in the configuration file. - -The ``args`` entry, when :func:`eval`\ uated in the context of the ``logging`` -package's namespace, is the list of arguments to the constructor for the handler -class. Refer to the constructors for the relevant handlers, or to the examples -below, to see how typical entries are constructed. :: - - [handler_hand02] - class=FileHandler - level=DEBUG - formatter=form02 - args=('python.log', 'w') - - [handler_hand03] - class=handlers.SocketHandler - level=INFO - formatter=form03 - args=('localhost', handlers.DEFAULT_TCP_LOGGING_PORT) - - [handler_hand04] - class=handlers.DatagramHandler - level=WARN - formatter=form04 - args=('localhost', handlers.DEFAULT_UDP_LOGGING_PORT) - - [handler_hand05] - class=handlers.SysLogHandler - level=ERROR - formatter=form05 - args=(('localhost', handlers.SYSLOG_UDP_PORT), handlers.SysLogHandler.LOG_USER) - - [handler_hand06] - class=handlers.NTEventLogHandler - level=CRITICAL - formatter=form06 - args=('Python Application', '', 'Application') - - [handler_hand07] - class=handlers.SMTPHandler - level=WARN - formatter=form07 - args=('localhost', 'from at abc', ['user1 at abc', 'user2 at xyz'], 'Logger Subject') - - [handler_hand08] - class=handlers.MemoryHandler - level=NOTSET - formatter=form08 - target= - args=(10, ERROR) - - [handler_hand09] - class=handlers.HTTPHandler - level=NOTSET - formatter=form09 - args=('localhost:9022', '/log', 'GET') - -Sections which specify formatter configuration are typified by the following. :: - - [formatter_form01] - format=F1 %(asctime)s %(levelname)s %(message)s - datefmt= - class=logging.Formatter - -The ``format`` entry is the overall format string, and the ``datefmt`` entry is -the :func:`strftime`\ -compatible date/time format string. If empty, the -package substitutes ISO8601 format date/times, which is almost equivalent to -specifying the date format string ``"%Y-%m-%d %H:%M:%S"``. The ISO8601 format -also specifies milliseconds, which are appended to the result of using the above -format string, with a comma separator. An example time in ISO8601 format is -``2003-01-23 00:29:50,411``. - -The ``class`` entry is optional. It indicates the name of the formatter's class -(as a dotted module and class name.) This option is useful for instantiating a -:class:`Formatter` subclass. Subclasses of :class:`Formatter` can present -exception tracebacks in an expanded or condensed format. - - -Configuration server example -^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Here is an example of a module using the logging configuration server:: - - import logging - import logging.config - import time - import os - - # read initial config file - logging.config.fileConfig("logging.conf") - - # create and start listener on port 9999 - t = logging.config.listen(9999) - t.start() - - logger = logging.getLogger("simpleExample") - - try: - # loop through logging calls to see the difference - # new configurations make, until Ctrl+C is pressed - while True: - logger.debug("debug message") - logger.info("info message") - logger.warn("warn message") - logger.error("error message") - logger.critical("critical message") - time.sleep(5) - except KeyboardInterrupt: - # cleanup - logging.config.stopListening() - t.join() - -And here is a script that takes a filename and sends that file to the server, -properly preceded with the binary-encoded length, as the new logging -configuration:: - - #!/usr/bin/env python - import socket, sys, struct - - data_to_send = open(sys.argv[1], "r").read() - - HOST = 'localhost' - PORT = 9999 - s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - print "connecting..." - s.connect((HOST, PORT)) - print "sending config..." - s.send(struct.pack(">L", len(data_to_send))) - s.send(data_to_send) - s.close() - print "complete" - - -More examples -------------- - -Multiple handlers and formatters -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Loggers are plain Python objects. The :func:`addHandler` method has no minimum -or maximum quota for the number of handlers you may add. Sometimes it will be -beneficial for an application to log all messages of all severities to a text -file while simultaneously logging errors or above to the console. To set this -up, simply configure the appropriate handlers. The logging calls in the -application code will remain unchanged. Here is a slight modification to the -previous simple module-based configuration example:: - - import logging - - logger = logging.getLogger("simple_example") - logger.setLevel(logging.DEBUG) - # create file handler which logs even debug messages - fh = logging.FileHandler("spam.log") - fh.setLevel(logging.DEBUG) - # create console handler with a higher log level - ch = logging.StreamHandler() - ch.setLevel(logging.ERROR) - # create formatter and add it to the handlers - formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s") - ch.setFormatter(formatter) - fh.setFormatter(formatter) - # add the handlers to logger - logger.addHandler(ch) - logger.addHandler(fh) - - # "application" code - logger.debug("debug message") - logger.info("info message") - logger.warn("warn message") - logger.error("error message") - logger.critical("critical message") - -Notice that the "application" code does not care about multiple handlers. All -that changed was the addition and configuration of a new handler named *fh*. - -The ability to create new handlers with higher- or lower-severity filters can be -very helpful when writing and testing an application. Instead of using many -``print`` statements for debugging, use ``logger.debug``: Unlike the print -statements, which you will have to delete or comment out later, the logger.debug -statements can remain intact in the source code and remain dormant until you -need them again. At that time, the only change that needs to happen is to -modify the severity level of the logger and/or handler to debug. - - -Using logging in multiple modules -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -It was mentioned above that multiple calls to -``logging.getLogger('someLogger')`` return a reference to the same logger -object. This is true not only within the same module, but also across modules -as long as it is in the same Python interpreter process. It is true for -references to the same object; additionally, application code can define and -configure a parent logger in one module and create (but not configure) a child -logger in a separate module, and all logger calls to the child will pass up to -the parent. Here is a main module:: - - import logging - import auxiliary_module - - # create logger with "spam_application" - logger = logging.getLogger("spam_application") - logger.setLevel(logging.DEBUG) - # create file handler which logs even debug messages - fh = logging.FileHandler("spam.log") - fh.setLevel(logging.DEBUG) - # create console handler with a higher log level - ch = logging.StreamHandler() - ch.setLevel(logging.ERROR) - # create formatter and add it to the handlers - formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s") - fh.setFormatter(formatter) - ch.setFormatter(formatter) - # add the handlers to the logger - logger.addHandler(fh) - logger.addHandler(ch) - - logger.info("creating an instance of auxiliary_module.Auxiliary") - a = auxiliary_module.Auxiliary() - logger.info("created an instance of auxiliary_module.Auxiliary") - logger.info("calling auxiliary_module.Auxiliary.do_something") - a.do_something() - logger.info("finished auxiliary_module.Auxiliary.do_something") - logger.info("calling auxiliary_module.some_function()") - auxiliary_module.some_function() - logger.info("done with auxiliary_module.some_function()") - -Here is the auxiliary module:: - - import logging - - # create logger - module_logger = logging.getLogger("spam_application.auxiliary") - - class Auxiliary: - def __init__(self): - self.logger = logging.getLogger("spam_application.auxiliary.Auxiliary") - self.logger.info("creating an instance of Auxiliary") - def do_something(self): - self.logger.info("doing something") - a = 1 + 1 - self.logger.info("done doing something") - - def some_function(): - module_logger.info("received a call to \"some_function\"") - -The output looks like this:: - - 2005-03-23 23:47:11,663 - spam_application - INFO - - creating an instance of auxiliary_module.Auxiliary - 2005-03-23 23:47:11,665 - spam_application.auxiliary.Auxiliary - INFO - - creating an instance of Auxiliary - 2005-03-23 23:47:11,665 - spam_application - INFO - - created an instance of auxiliary_module.Auxiliary - 2005-03-23 23:47:11,668 - spam_application - INFO - - calling auxiliary_module.Auxiliary.do_something - 2005-03-23 23:47:11,668 - spam_application.auxiliary.Auxiliary - INFO - - doing something - 2005-03-23 23:47:11,669 - spam_application.auxiliary.Auxiliary - INFO - - done doing something - 2005-03-23 23:47:11,670 - spam_application - INFO - - finished auxiliary_module.Auxiliary.do_something - 2005-03-23 23:47:11,671 - spam_application - INFO - - calling auxiliary_module.some_function() - 2005-03-23 23:47:11,672 - spam_application.auxiliary - INFO - - received a call to "some_function" - 2005-03-23 23:47:11,673 - spam_application - INFO - - done with auxiliary_module.some_function() - -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 8 12:59:13 2011 From: python-checkins at python.org (victor.stinner) Date: Fri, 08 Apr 2011 12:59:13 +0200 Subject: [Python-checkins] cpython: faulthandler: fix unregister() if it is called before register() Message-ID: http://hg.python.org/cpython/rev/145d0a56c8bd changeset: 69205:145d0a56c8bd parent: 69203:5ec2695c9c15 user: Victor Stinner date: Fri Apr 08 12:48:15 2011 +0200 summary: faulthandler: fix unregister() if it is called before register() Fix a crash: don't read from NULL. files: Doc/library/faulthandler.rst | 3 ++- Modules/faulthandler.c | 3 +++ 2 files changed, 5 insertions(+), 1 deletions(-) diff --git a/Doc/library/faulthandler.rst b/Doc/library/faulthandler.rst --- a/Doc/library/faulthandler.rst +++ b/Doc/library/faulthandler.rst @@ -97,7 +97,8 @@ .. function:: unregister(signum) Unregister a user signal: uninstall the handler of the *signum* signal - installed by :func:`register`. + installed by :func:`register`. Return ``True`` if the signal was registered, + ``False`` otherwise. Not available on Windows. diff --git a/Modules/faulthandler.c b/Modules/faulthandler.c --- a/Modules/faulthandler.c +++ b/Modules/faulthandler.c @@ -694,6 +694,9 @@ if (!check_signum(signum)) return NULL; + if (user_signals == NULL) + Py_RETURN_FALSE; + user = &user_signals[signum]; change = faulthandler_unregister(user, signum); return PyBool_FromLong(change); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 8 12:59:15 2011 From: python-checkins at python.org (victor.stinner) Date: Fri, 08 Apr 2011 12:59:15 +0200 Subject: [Python-checkins] cpython: faulthandler: one more time, fix usage of locks in the watchdog thread Message-ID: http://hg.python.org/cpython/rev/e409d9beaf6b changeset: 69206:e409d9beaf6b user: Victor Stinner date: Fri Apr 08 12:57:06 2011 +0200 summary: faulthandler: one more time, fix usage of locks in the watchdog thread * Write a new test to ensure that dump_tracebacks_later() still works if it was already called and then cancelled before * Don't use a variable to check the status of the thread, only rely on locks * The thread only releases cancel_event if it was able to acquire it (if the timer was interrupted) * The main thread always hold this lock. It is only released when faulthandler_thread() is interrupted until this thread exits, or at Python exit. files: Lib/test/test_faulthandler.py | 45 ++++++++++------- Modules/faulthandler.c | 57 +++++++++++----------- 2 files changed, 55 insertions(+), 47 deletions(-) diff --git a/Lib/test/test_faulthandler.py b/Lib/test/test_faulthandler.py --- a/Lib/test/test_faulthandler.py +++ b/Lib/test/test_faulthandler.py @@ -352,7 +352,7 @@ with temporary_filename() as filename: self.check_dump_traceback_threads(filename) - def _check_dump_tracebacks_later(self, repeat, cancel, filename): + def _check_dump_tracebacks_later(self, repeat, cancel, filename, loops): """ Check how many times the traceback is written in timeout x 2.5 seconds, or timeout x 3.5 seconds if cancel is True: 1, 2 or 3 times depending @@ -364,42 +364,43 @@ import faulthandler import time -def func(repeat, cancel, timeout): - if cancel: +def func(timeout, repeat, cancel, file, loops): + for loop in range(loops): + faulthandler.dump_tracebacks_later(timeout, repeat=repeat, file=file) + if cancel: + faulthandler.cancel_dump_tracebacks_later() + time.sleep(timeout * 2.5) faulthandler.cancel_dump_tracebacks_later() - time.sleep(timeout * 2.5) - faulthandler.cancel_dump_tracebacks_later() timeout = {timeout} repeat = {repeat} cancel = {cancel} +loops = {loops} if {has_filename}: file = open({filename}, "wb") else: file = None -faulthandler.dump_tracebacks_later(timeout, - repeat=repeat, file=file) -func(repeat, cancel, timeout) +func(timeout, repeat, cancel, file, loops) if file is not None: file.close() """.strip() code = code.format( - filename=repr(filename), - has_filename=bool(filename), + timeout=TIMEOUT, repeat=repeat, cancel=cancel, - timeout=TIMEOUT, + loops=loops, + has_filename=bool(filename), + filename=repr(filename), ) trace, exitcode = self.get_output(code, filename) trace = '\n'.join(trace) if not cancel: + count = loops if repeat: - count = 2 - else: - count = 1 + count *= 2 header = 'Thread 0x[0-9a-f]+:\n' - regex = expected_traceback(7, 19, header, count=count) + regex = expected_traceback(9, 20, header, count=count) self.assertRegex(trace, regex) else: self.assertEqual(trace, '') @@ -408,12 +409,17 @@ @unittest.skipIf(not hasattr(faulthandler, 'dump_tracebacks_later'), 'need faulthandler.dump_tracebacks_later()') def check_dump_tracebacks_later(self, repeat=False, cancel=False, - file=False): + file=False, twice=False): + if twice: + loops = 2 + else: + loops = 1 if file: with temporary_filename() as filename: - self._check_dump_tracebacks_later(repeat, cancel, filename) + self._check_dump_tracebacks_later(repeat, cancel, + filename, loops) else: - self._check_dump_tracebacks_later(repeat, cancel, None) + self._check_dump_tracebacks_later(repeat, cancel, None, loops) def test_dump_tracebacks_later(self): self.check_dump_tracebacks_later() @@ -427,6 +433,9 @@ def test_dump_tracebacks_later_file(self): self.check_dump_tracebacks_later(file=True) + def test_dump_tracebacks_later_twice(self): + self.check_dump_tracebacks_later(twice=True) + @unittest.skipIf(not hasattr(faulthandler, "register"), "need faulthandler.register") def check_register(self, filename=False, all_threads=False, diff --git a/Modules/faulthandler.c b/Modules/faulthandler.c --- a/Modules/faulthandler.c +++ b/Modules/faulthandler.c @@ -48,13 +48,14 @@ int fd; PY_TIMEOUT_T timeout_ms; /* timeout in microseconds */ int repeat; - int running; PyInterpreterState *interp; int exit; - /* released by parent thread when cancel request */ + /* The main thread always hold this lock. It is only released when + faulthandler_thread() is interrupted until this thread exits, or at + Python exit. */ PyThread_type_lock cancel_event; /* released by child thread when joined */ - PyThread_type_lock join_event; + PyThread_type_lock running; } thread; #endif @@ -414,7 +415,7 @@ st = PyThread_acquire_lock_timed(thread.cancel_event, thread.timeout_ms, 0); if (st == PY_LOCK_ACQUIRED) { - /* Cancelled by user */ + PyThread_release_lock(thread.cancel_event); break; } /* Timeout => dump traceback */ @@ -431,21 +432,22 @@ } while (ok && thread.repeat); /* The only way out */ - PyThread_release_lock(thread.cancel_event); - PyThread_release_lock(thread.join_event); + PyThread_release_lock(thread.running); } static void -faulthandler_cancel_dump_tracebacks_later(void) +cancel_dump_tracebacks_later(void) { - if (thread.running) { - /* Notify cancellation */ - PyThread_release_lock(thread.cancel_event); - } + /* notify cancellation */ + PyThread_release_lock(thread.cancel_event); + /* Wait for thread to join */ - PyThread_acquire_lock(thread.join_event, 1); - PyThread_release_lock(thread.join_event); - thread.running = 0; + PyThread_acquire_lock(thread.running, 1); + PyThread_release_lock(thread.running); + + /* The main thread should always hold the cancel_event lock */ + PyThread_acquire_lock(thread.cancel_event, 1); + Py_CLEAR(thread.file); } @@ -489,7 +491,7 @@ return NULL; /* Cancel previous thread, if running */ - faulthandler_cancel_dump_tracebacks_later(); + cancel_dump_tracebacks_later(); Py_XDECREF(thread.file); Py_INCREF(file); @@ -501,14 +503,10 @@ thread.exit = exit; /* Arm these locks to serve as events when released */ - PyThread_acquire_lock(thread.join_event, 1); - PyThread_acquire_lock(thread.cancel_event, 1); + PyThread_acquire_lock(thread.running, 1); - thread.running = 1; if (PyThread_start_new_thread(faulthandler_thread, NULL) == -1) { - thread.running = 0; - PyThread_release_lock(thread.join_event); - PyThread_release_lock(thread.cancel_event); + PyThread_release_lock(thread.running); Py_CLEAR(thread.file); PyErr_SetString(PyExc_RuntimeError, "unable to start watchdog thread"); @@ -521,7 +519,7 @@ static PyObject* faulthandler_cancel_dump_tracebacks_later_py(PyObject *self) { - faulthandler_cancel_dump_tracebacks_later(); + cancel_dump_tracebacks_later(); Py_RETURN_NONE; } #endif /* FAULTHANDLER_LATER */ @@ -1001,15 +999,15 @@ } #endif #ifdef FAULTHANDLER_LATER - thread.running = 0; thread.file = NULL; thread.cancel_event = PyThread_allocate_lock(); - thread.join_event = PyThread_allocate_lock(); - if (!thread.cancel_event || !thread.join_event) { + thread.running = PyThread_allocate_lock(); + if (!thread.cancel_event || !thread.running) { PyErr_SetString(PyExc_RuntimeError, "could not allocate locks for faulthandler"); return -1; } + PyThread_acquire_lock(thread.cancel_event, 1); #endif return faulthandler_env_options(); @@ -1023,14 +1021,15 @@ #ifdef FAULTHANDLER_LATER /* later */ - faulthandler_cancel_dump_tracebacks_later(); + cancel_dump_tracebacks_later(); if (thread.cancel_event) { + PyThread_release_lock(thread.cancel_event); PyThread_free_lock(thread.cancel_event); thread.cancel_event = NULL; } - if (thread.join_event) { - PyThread_free_lock(thread.join_event); - thread.join_event = NULL; + if (thread.running) { + PyThread_free_lock(thread.running); + thread.running = NULL; } #endif -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 8 13:40:08 2011 From: python-checkins at python.org (victor.stinner) Date: Fri, 08 Apr 2011 13:40:08 +0200 Subject: [Python-checkins] cpython: faulthandler: fix variable name, timeout_ms => timeout_us Message-ID: http://hg.python.org/cpython/rev/0c39e067f35a changeset: 69207:0c39e067f35a user: Victor Stinner date: Fri Apr 08 13:00:31 2011 +0200 summary: faulthandler: fix variable name, timeout_ms => timeout_us The comment was already correct. files: Modules/faulthandler.c | 12 ++++++------ 1 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Modules/faulthandler.c b/Modules/faulthandler.c --- a/Modules/faulthandler.c +++ b/Modules/faulthandler.c @@ -46,7 +46,7 @@ static struct { PyObject *file; int fd; - PY_TIMEOUT_T timeout_ms; /* timeout in microseconds */ + PY_TIMEOUT_T timeout_us; /* timeout in microseconds */ int repeat; PyInterpreterState *interp; int exit; @@ -413,7 +413,7 @@ do { st = PyThread_acquire_lock_timed(thread.cancel_event, - thread.timeout_ms, 0); + thread.timeout_us, 0); if (st == PY_LOCK_ACQUIRED) { PyThread_release_lock(thread.cancel_event); break; @@ -457,7 +457,7 @@ { static char *kwlist[] = {"timeout", "repeat", "file", "exit", NULL}; double timeout; - PY_TIMEOUT_T timeout_ms; + PY_TIMEOUT_T timeout_us; int repeat = 0; PyObject *file = NULL; int fd; @@ -473,8 +473,8 @@ PyErr_SetString(PyExc_OverflowError, "timeout value is too large"); return NULL; } - timeout_ms = (PY_TIMEOUT_T)timeout; - if (timeout_ms <= 0) { + timeout_us = (PY_TIMEOUT_T)timeout; + if (timeout_us <= 0) { PyErr_SetString(PyExc_ValueError, "timeout must be greater than 0"); return NULL; } @@ -497,7 +497,7 @@ Py_INCREF(file); thread.file = file; thread.fd = fd; - thread.timeout_ms = timeout_ms; + thread.timeout_us = timeout_us; thread.repeat = repeat; thread.interp = tstate->interp; thread.exit = exit; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 8 13:40:17 2011 From: python-checkins at python.org (victor.stinner) Date: Fri, 08 Apr 2011 13:40:17 +0200 Subject: [Python-checkins] cpython: faulthandler: dump_tracebacks_later() displays also the timeout Message-ID: http://hg.python.org/cpython/rev/7af470b0fa5e changeset: 69208:7af470b0fa5e user: Victor Stinner date: Fri Apr 08 13:39:59 2011 +0200 summary: faulthandler: dump_tracebacks_later() displays also the timeout files: Lib/test/test_faulthandler.py | 4 +- Modules/faulthandler.c | 52 +++++++++++++++++++++- 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_faulthandler.py b/Lib/test/test_faulthandler.py --- a/Lib/test/test_faulthandler.py +++ b/Lib/test/test_faulthandler.py @@ -1,4 +1,5 @@ from contextlib import contextmanager +import datetime import faulthandler import re import signal @@ -360,6 +361,7 @@ Raise an error if the output doesn't match the expect format. """ + timeout_str = str(datetime.timedelta(seconds=TIMEOUT)) code = """ import faulthandler import time @@ -399,7 +401,7 @@ count = loops if repeat: count *= 2 - header = 'Thread 0x[0-9a-f]+:\n' + header = r'Timeout \(%s\)!\nThread 0x[0-9a-f]+:\n' % timeout_str regex = expected_traceback(9, 20, header, count=count) self.assertRegex(trace, regex) else: diff --git a/Modules/faulthandler.c b/Modules/faulthandler.c --- a/Modules/faulthandler.c +++ b/Modules/faulthandler.c @@ -50,6 +50,8 @@ int repeat; PyInterpreterState *interp; int exit; + char *header; + size_t header_len; /* The main thread always hold this lock. It is only released when faulthandler_thread() is interrupted until this thread exits, or at Python exit. */ @@ -424,6 +426,8 @@ /* get the thread holding the GIL, NULL if no thread hold the GIL */ current = _Py_atomic_load_relaxed(&_PyThreadState_Current); + write(thread.fd, thread.header, thread.header_len); + errmsg = _Py_DumpTracebackThreads(thread.fd, thread.interp, current); ok = (errmsg == NULL); @@ -449,6 +453,37 @@ PyThread_acquire_lock(thread.cancel_event, 1); Py_CLEAR(thread.file); + if (thread.header) { + free(thread.header); + thread.header = NULL; + } +} + +static char* +format_timeout(double timeout) +{ + unsigned long us, sec, min, hour; + double intpart, fracpart; + char buffer[100]; + + fracpart = modf(timeout, &intpart); + sec = (unsigned long)intpart; + us = (unsigned long)(fracpart * 1e6); + min = sec / 60; + sec %= 60; + hour = min / 60; + min %= 60; + + if (us != 0) + PyOS_snprintf(buffer, sizeof(buffer), + "Timeout (%lu:%02lu:%02lu.%06lu)!\n", + hour, min, sec, us); + else + PyOS_snprintf(buffer, sizeof(buffer), + "Timeout (%lu:%02lu:%02lu)!\n", + hour, min, sec); + + return strdup(buffer); } static PyObject* @@ -463,17 +498,18 @@ int fd; int exit = 0; PyThreadState *tstate; + char *header; + size_t header_len; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "d|iOi:dump_tracebacks_later", kwlist, &timeout, &repeat, &file, &exit)) return NULL; - timeout *= 1e6; - if (timeout >= (double) PY_TIMEOUT_MAX) { + if ((timeout * 1e6) >= (double) PY_TIMEOUT_MAX) { PyErr_SetString(PyExc_OverflowError, "timeout value is too large"); return NULL; } - timeout_us = (PY_TIMEOUT_T)timeout; + timeout_us = (PY_TIMEOUT_T)(timeout * 1e6); if (timeout_us <= 0) { PyErr_SetString(PyExc_ValueError, "timeout must be greater than 0"); return NULL; @@ -490,6 +526,12 @@ if (file == NULL) return NULL; + /* format the timeout */ + header = format_timeout(timeout); + if (header == NULL) + return PyErr_NoMemory(); + header_len = strlen(header); + /* Cancel previous thread, if running */ cancel_dump_tracebacks_later(); @@ -501,6 +543,8 @@ thread.repeat = repeat; thread.interp = tstate->interp; thread.exit = exit; + thread.header = header; + thread.header_len = header_len; /* Arm these locks to serve as events when released */ PyThread_acquire_lock(thread.running, 1); @@ -508,6 +552,8 @@ if (PyThread_start_new_thread(faulthandler_thread, NULL) == -1) { PyThread_release_lock(thread.running); Py_CLEAR(thread.file); + free(header); + thread.header = NULL; PyErr_SetString(PyExc_RuntimeError, "unable to start watchdog thread"); return NULL; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 9 00:51:27 2011 From: python-checkins at python.org (victor.stinner) Date: Sat, 09 Apr 2011 00:51:27 +0200 Subject: [Python-checkins] cpython: Improve faulthandler.enable(all_threads=True) Message-ID: http://hg.python.org/cpython/rev/78a66c98288d changeset: 69209:78a66c98288d user: Victor Stinner date: Sat Apr 09 00:47:23 2011 +0200 summary: Improve faulthandler.enable(all_threads=True) faulthandler.enable(all_threads=True) dumps the tracebacks even if it is not possible to get the state of the current thread Create also the get_thread_state() subfunction to factorize the code. files: Modules/faulthandler.c | 54 +++++++++++++++++------------ 1 files changed, 32 insertions(+), 22 deletions(-) diff --git a/Modules/faulthandler.c b/Modules/faulthandler.c --- a/Modules/faulthandler.c +++ b/Modules/faulthandler.c @@ -40,6 +40,7 @@ PyObject *file; int fd; int all_threads; + PyInterpreterState *interp; } fatal_error = {0, NULL, -1, 0}; #ifdef FAULTHANDLER_LATER @@ -165,6 +166,20 @@ return file; } +/* Get the state of the current thread: only call this function if the current + thread holds the GIL. Raise an exception on error. */ +static PyThreadState* +get_thread_state(void) +{ + PyThreadState *tstate = PyThreadState_Get(); + if (tstate == NULL) { + PyErr_SetString(PyExc_RuntimeError, + "unable to get the current thread state"); + return NULL; + } + return tstate; +} + static PyObject* faulthandler_dump_traceback_py(PyObject *self, PyObject *args, PyObject *kwargs) @@ -185,13 +200,9 @@ if (file == NULL) return NULL; - /* The caller holds the GIL and so PyThreadState_Get() can be used */ - tstate = PyThreadState_Get(); - if (tstate == NULL) { - PyErr_SetString(PyExc_RuntimeError, - "unable to get the current thread state"); + tstate = get_thread_state(); + if (tstate == NULL) return NULL; - } if (all_threads) { errmsg = _Py_DumpTracebackThreads(fd, tstate->interp, tstate); @@ -266,13 +277,13 @@ #else tstate = PyThreadState_Get(); #endif - if (tstate == NULL) - return; if (fatal_error.all_threads) - _Py_DumpTracebackThreads(fd, tstate->interp, tstate); - else - _Py_DumpTraceback(fd, tstate); + _Py_DumpTracebackThreads(fd, fatal_error.interp, tstate); + else { + if (tstate != NULL) + _Py_DumpTraceback(fd, tstate); + } #ifdef MS_WINDOWS if (signum == SIGSEGV) { @@ -301,6 +312,7 @@ #endif int err; int fd; + PyThreadState *tstate; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|Oi:enable", kwlist, &file, &all_threads)) @@ -310,11 +322,16 @@ if (file == NULL) return NULL; + tstate = get_thread_state(); + if (tstate == NULL) + return NULL; + Py_XDECREF(fatal_error.file); Py_INCREF(file); fatal_error.file = file; fatal_error.fd = fd; fatal_error.all_threads = all_threads; + fatal_error.interp = tstate->interp; if (!fatal_error.enabled) { fatal_error.enabled = 1; @@ -515,12 +532,9 @@ return NULL; } - tstate = PyThreadState_Get(); - if (tstate == NULL) { - PyErr_SetString(PyExc_RuntimeError, - "unable to get the current thread state"); + tstate = get_thread_state(); + if (tstate == NULL) return NULL; - } file = faulthandler_get_fileno(file, &fd); if (file == NULL) @@ -652,13 +666,9 @@ if (!check_signum(signum)) return NULL; - /* The caller holds the GIL and so PyThreadState_Get() can be used */ - tstate = PyThreadState_Get(); - if (tstate == NULL) { - PyErr_SetString(PyExc_RuntimeError, - "unable to get the current thread state"); + tstate = get_thread_state(); + if (tstate == NULL) return NULL; - } file = faulthandler_get_fileno(file, &fd); if (file == NULL) -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Sat Apr 9 04:57:07 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sat, 09 Apr 2011 04:57:07 +0200 Subject: [Python-checkins] Daily reference leaks (78a66c98288d): sum=0 Message-ID: results for 78a66c98288d on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogmwFbNS', '-x'] From python-checkins at python.org Sat Apr 9 16:02:02 2011 From: python-checkins at python.org (victor.stinner) Date: Sat, 09 Apr 2011 16:02:02 +0200 Subject: [Python-checkins] cpython (3.1): Issue #11650: PyOS_StdioReadline() retries fgets() if it was interrupted Message-ID: http://hg.python.org/cpython/rev/2222f343ac51 changeset: 69210:2222f343ac51 branch: 3.1 parent: 69201:10725fc76e11 user: Victor Stinner date: Sat Apr 09 15:55:44 2011 +0200 summary: Issue #11650: PyOS_StdioReadline() retries fgets() if it was interrupted (EINTR), for example if the program is stopped with CTRL+z on Mac OS X. Patch written by Charles-Francois Natali. files: Misc/NEWS | 4 ++++ Parser/myreadline.c | 9 +++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,10 @@ Core and Builtins ----------------- +- Issue #11650: PyOS_StdioReadline() retries fgets() if it was interrupted + (EINTR), for example if the program is stopped with CTRL+z on Mac OS X. Patch + written by Charles-Francois Natali. + - Issue #8651: PyArg_Parse*() functions raise an OverflowError if the file doesn't have PY_SSIZE_T_CLEAN define and the size doesn't fit in an int (length bigger than 2^31-1 bytes). diff --git a/Parser/myreadline.c b/Parser/myreadline.c --- a/Parser/myreadline.c +++ b/Parser/myreadline.c @@ -36,7 +36,7 @@ my_fgets(char *buf, int len, FILE *fp) { char *p; - for (;;) { + while (1) { if (PyOS_InputHook != NULL) (void)(PyOS_InputHook)(); errno = 0; @@ -85,9 +85,10 @@ #ifdef WITH_THREAD PyEval_SaveThread(); #endif - if (s < 0) { - return 1; - } + if (s < 0) + return 1; + /* try again */ + continue; } #endif if (PyOS_InterruptOccurred()) { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 9 16:02:03 2011 From: python-checkins at python.org (victor.stinner) Date: Sat, 09 Apr 2011 16:02:03 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): (Merge 3.1) Issue #11650: PyOS_StdioReadline() retries fgets() if it was Message-ID: http://hg.python.org/cpython/rev/fc2f251e660a changeset: 69211:fc2f251e660a branch: 3.2 parent: 69202:74ec64dc3538 parent: 69210:2222f343ac51 user: Victor Stinner date: Sat Apr 09 15:59:25 2011 +0200 summary: (Merge 3.1) Issue #11650: PyOS_StdioReadline() retries fgets() if it was interrupted (EINTR), for example if the program is stopped with CTRL+z on Mac OS X. Patch written by Charles-Francois Natali. files: Misc/NEWS | 4 + Parser/myreadline.c | 106 ++++++++++++++++--------------- 2 files changed, 59 insertions(+), 51 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,10 @@ Core and Builtins ----------------- +- Issue #11650: PyOS_StdioReadline() retries fgets() if it was interrupted + (EINTR), for example if the program is stopped with CTRL+z on Mac OS X. Patch + written by Charles-Francois Natali. + - Issue #11395: io.FileIO().write() clamps the data length to 32,767 bytes on Windows if the file is a TTY to workaround a Windows bug. The Windows console returns an error (12: not enough space error) on writing into stdout if diff --git a/Parser/myreadline.c b/Parser/myreadline.c --- a/Parser/myreadline.c +++ b/Parser/myreadline.c @@ -36,63 +36,67 @@ my_fgets(char *buf, int len, FILE *fp) { char *p; - if (PyOS_InputHook != NULL) - (void)(PyOS_InputHook)(); - errno = 0; - p = fgets(buf, len, fp); - if (p != NULL) - return 0; /* No error */ + while (1) { + if (PyOS_InputHook != NULL) + (void)(PyOS_InputHook)(); + errno = 0; + p = fgets(buf, len, fp); + if (p != NULL) + return 0; /* No error */ #ifdef MS_WINDOWS - /* In the case of a Ctrl+C or some other external event - interrupting the operation: - Win2k/NT: ERROR_OPERATION_ABORTED is the most recent Win32 - error code (and feof() returns TRUE). - Win9x: Ctrl+C seems to have no effect on fgets() returning - early - the signal handler is called, but the fgets() - only returns "normally" (ie, when Enter hit or feof()) - */ - if (GetLastError()==ERROR_OPERATION_ABORTED) { - /* Signals come asynchronously, so we sleep a brief - moment before checking if the handler has been - triggered (we cant just return 1 before the - signal handler has been called, as the later - signal may be treated as a separate interrupt). + /* In the case of a Ctrl+C or some other external event + interrupting the operation: + Win2k/NT: ERROR_OPERATION_ABORTED is the most recent Win32 + error code (and feof() returns TRUE). + Win9x: Ctrl+C seems to have no effect on fgets() returning + early - the signal handler is called, but the fgets() + only returns "normally" (ie, when Enter hit or feof()) */ - Sleep(1); + if (GetLastError()==ERROR_OPERATION_ABORTED) { + /* Signals come asynchronously, so we sleep a brief + moment before checking if the handler has been + triggered (we cant just return 1 before the + signal handler has been called, as the later + signal may be treated as a separate interrupt). + */ + Sleep(1); + if (PyOS_InterruptOccurred()) { + return 1; /* Interrupt */ + } + /* Either the sleep wasn't long enough (need a + short loop retrying?) or not interrupted at all + (in which case we should revisit the whole thing!) + Logging some warning would be nice. assert is not + viable as under the debugger, the various dialogs + mean the condition is not true. + */ + } +#endif /* MS_WINDOWS */ + if (feof(fp)) { + return -1; /* EOF */ + } +#ifdef EINTR + if (errno == EINTR) { + int s; +#ifdef WITH_THREAD + PyEval_RestoreThread(_PyOS_ReadlineTState); +#endif + s = PyErr_CheckSignals(); +#ifdef WITH_THREAD + PyEval_SaveThread(); +#endif + if (s < 0) + return 1; + /* try again */ + continue; + } +#endif if (PyOS_InterruptOccurred()) { return 1; /* Interrupt */ } - /* Either the sleep wasn't long enough (need a - short loop retrying?) or not interrupted at all - (in which case we should revisit the whole thing!) - Logging some warning would be nice. assert is not - viable as under the debugger, the various dialogs - mean the condition is not true. - */ + return -2; /* Error */ } -#endif /* MS_WINDOWS */ - if (feof(fp)) { - return -1; /* EOF */ - } -#ifdef EINTR - if (errno == EINTR) { - int s; -#ifdef WITH_THREAD - PyEval_RestoreThread(_PyOS_ReadlineTState); -#endif - s = PyErr_CheckSignals(); -#ifdef WITH_THREAD - PyEval_SaveThread(); -#endif - if (s < 0) { - return 1; - } - } -#endif - if (PyOS_InterruptOccurred()) { - return 1; /* Interrupt */ - } - return -2; /* Error */ + /* NOTREACHED */ } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 9 16:02:06 2011 From: python-checkins at python.org (victor.stinner) Date: Sat, 09 Apr 2011 16:02:06 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): (Merge 3.2) Issue #11650: PyOS_StdioReadline() retries fgets() if it was Message-ID: http://hg.python.org/cpython/rev/64de1ded0744 changeset: 69212:64de1ded0744 parent: 69209:78a66c98288d parent: 69211:fc2f251e660a user: Victor Stinner date: Sat Apr 09 16:01:55 2011 +0200 summary: (Merge 3.2) Issue #11650: PyOS_StdioReadline() retries fgets() if it was interrupted (EINTR), for example if the program is stopped with CTRL+z on Mac OS X. Patch written by Charles-Francois Natali. files: Misc/NEWS | 4 + Parser/myreadline.c | 106 ++++++++++++++++--------------- 2 files changed, 59 insertions(+), 51 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,10 @@ Core and Builtins ----------------- +- Issue #11650: PyOS_StdioReadline() retries fgets() if it was interrupted + (EINTR), for example if the program is stopped with CTRL+z on Mac OS X. Patch + written by Charles-Francois Natali. + - Issue #9319: Include the filename in "Non-UTF8 code ..." syntax error. - Issue #10785: Store the filename as Unicode in the Python parser. diff --git a/Parser/myreadline.c b/Parser/myreadline.c --- a/Parser/myreadline.c +++ b/Parser/myreadline.c @@ -36,63 +36,67 @@ my_fgets(char *buf, int len, FILE *fp) { char *p; - if (PyOS_InputHook != NULL) - (void)(PyOS_InputHook)(); - errno = 0; - p = fgets(buf, len, fp); - if (p != NULL) - return 0; /* No error */ + while (1) { + if (PyOS_InputHook != NULL) + (void)(PyOS_InputHook)(); + errno = 0; + p = fgets(buf, len, fp); + if (p != NULL) + return 0; /* No error */ #ifdef MS_WINDOWS - /* In the case of a Ctrl+C or some other external event - interrupting the operation: - Win2k/NT: ERROR_OPERATION_ABORTED is the most recent Win32 - error code (and feof() returns TRUE). - Win9x: Ctrl+C seems to have no effect on fgets() returning - early - the signal handler is called, but the fgets() - only returns "normally" (ie, when Enter hit or feof()) - */ - if (GetLastError()==ERROR_OPERATION_ABORTED) { - /* Signals come asynchronously, so we sleep a brief - moment before checking if the handler has been - triggered (we cant just return 1 before the - signal handler has been called, as the later - signal may be treated as a separate interrupt). + /* In the case of a Ctrl+C or some other external event + interrupting the operation: + Win2k/NT: ERROR_OPERATION_ABORTED is the most recent Win32 + error code (and feof() returns TRUE). + Win9x: Ctrl+C seems to have no effect on fgets() returning + early - the signal handler is called, but the fgets() + only returns "normally" (ie, when Enter hit or feof()) */ - Sleep(1); + if (GetLastError()==ERROR_OPERATION_ABORTED) { + /* Signals come asynchronously, so we sleep a brief + moment before checking if the handler has been + triggered (we cant just return 1 before the + signal handler has been called, as the later + signal may be treated as a separate interrupt). + */ + Sleep(1); + if (PyOS_InterruptOccurred()) { + return 1; /* Interrupt */ + } + /* Either the sleep wasn't long enough (need a + short loop retrying?) or not interrupted at all + (in which case we should revisit the whole thing!) + Logging some warning would be nice. assert is not + viable as under the debugger, the various dialogs + mean the condition is not true. + */ + } +#endif /* MS_WINDOWS */ + if (feof(fp)) { + return -1; /* EOF */ + } +#ifdef EINTR + if (errno == EINTR) { + int s; +#ifdef WITH_THREAD + PyEval_RestoreThread(_PyOS_ReadlineTState); +#endif + s = PyErr_CheckSignals(); +#ifdef WITH_THREAD + PyEval_SaveThread(); +#endif + if (s < 0) + return 1; + /* try again */ + continue; + } +#endif if (PyOS_InterruptOccurred()) { return 1; /* Interrupt */ } - /* Either the sleep wasn't long enough (need a - short loop retrying?) or not interrupted at all - (in which case we should revisit the whole thing!) - Logging some warning would be nice. assert is not - viable as under the debugger, the various dialogs - mean the condition is not true. - */ + return -2; /* Error */ } -#endif /* MS_WINDOWS */ - if (feof(fp)) { - return -1; /* EOF */ - } -#ifdef EINTR - if (errno == EINTR) { - int s; -#ifdef WITH_THREAD - PyEval_RestoreThread(_PyOS_ReadlineTState); -#endif - s = PyErr_CheckSignals(); -#ifdef WITH_THREAD - PyEval_SaveThread(); -#endif - if (s < 0) { - return 1; - } - } -#endif - if (PyOS_InterruptOccurred()) { - return 1; /* Interrupt */ - } - return -2; /* Error */ + /* NOTREACHED */ } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 9 16:09:17 2011 From: python-checkins at python.org (victor.stinner) Date: Sat, 09 Apr 2011 16:09:17 +0200 Subject: [Python-checkins] cpython (2.7): (Merge 3.1) Issue #11650: PyOS_StdioReadline() retries fgets() if it was Message-ID: http://hg.python.org/cpython/rev/7febd5ef7619 changeset: 69213:7febd5ef7619 branch: 2.7 parent: 69204:6fb033af9310 user: Victor Stinner date: Sat Apr 09 16:09:08 2011 +0200 summary: (Merge 3.1) Issue #11650: PyOS_StdioReadline() retries fgets() if it was interrupted (EINTR), for example if the program is stopped with CTRL+z on Mac OS X. Patch written by Charles-Francois Natali. files: Misc/NEWS | 4 + Parser/myreadline.c | 106 ++++++++++++++++--------------- 2 files changed, 59 insertions(+), 51 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -9,6 +9,10 @@ Core and Builtins ----------------- +- Issue #11650: PyOS_StdioReadline() retries fgets() if it was interrupted + (EINTR), for example if the program is stopped with CTRL+z on Mac OS X. Patch + written by Charles-Francois Natali. + - Issue #11144: Ensure that int(a_float) returns an int whenever possible. Previously, there were some corner cases where a long was returned even though the result was within the range of an int. diff --git a/Parser/myreadline.c b/Parser/myreadline.c --- a/Parser/myreadline.c +++ b/Parser/myreadline.c @@ -40,63 +40,67 @@ my_fgets(char *buf, int len, FILE *fp) { char *p; - if (PyOS_InputHook != NULL) - (void)(PyOS_InputHook)(); - errno = 0; - p = fgets(buf, len, fp); - if (p != NULL) - return 0; /* No error */ + while (1) { + if (PyOS_InputHook != NULL) + (void)(PyOS_InputHook)(); + errno = 0; + p = fgets(buf, len, fp); + if (p != NULL) + return 0; /* No error */ #ifdef MS_WINDOWS - /* In the case of a Ctrl+C or some other external event - interrupting the operation: - Win2k/NT: ERROR_OPERATION_ABORTED is the most recent Win32 - error code (and feof() returns TRUE). - Win9x: Ctrl+C seems to have no effect on fgets() returning - early - the signal handler is called, but the fgets() - only returns "normally" (ie, when Enter hit or feof()) - */ - if (GetLastError()==ERROR_OPERATION_ABORTED) { - /* Signals come asynchronously, so we sleep a brief - moment before checking if the handler has been - triggered (we cant just return 1 before the - signal handler has been called, as the later - signal may be treated as a separate interrupt). + /* In the case of a Ctrl+C or some other external event + interrupting the operation: + Win2k/NT: ERROR_OPERATION_ABORTED is the most recent Win32 + error code (and feof() returns TRUE). + Win9x: Ctrl+C seems to have no effect on fgets() returning + early - the signal handler is called, but the fgets() + only returns "normally" (ie, when Enter hit or feof()) */ - Sleep(1); + if (GetLastError()==ERROR_OPERATION_ABORTED) { + /* Signals come asynchronously, so we sleep a brief + moment before checking if the handler has been + triggered (we cant just return 1 before the + signal handler has been called, as the later + signal may be treated as a separate interrupt). + */ + Sleep(1); + if (PyOS_InterruptOccurred()) { + return 1; /* Interrupt */ + } + /* Either the sleep wasn't long enough (need a + short loop retrying?) or not interrupted at all + (in which case we should revisit the whole thing!) + Logging some warning would be nice. assert is not + viable as under the debugger, the various dialogs + mean the condition is not true. + */ + } +#endif /* MS_WINDOWS */ + if (feof(fp)) { + return -1; /* EOF */ + } +#ifdef EINTR + if (errno == EINTR) { + int s; +#ifdef WITH_THREAD + PyEval_RestoreThread(_PyOS_ReadlineTState); +#endif + s = PyErr_CheckSignals(); +#ifdef WITH_THREAD + PyEval_SaveThread(); +#endif + if (s < 0) + return 1; + /* try again */ + continue; + } +#endif if (PyOS_InterruptOccurred()) { return 1; /* Interrupt */ } - /* Either the sleep wasn't long enough (need a - short loop retrying?) or not interrupted at all - (in which case we should revisit the whole thing!) - Logging some warning would be nice. assert is not - viable as under the debugger, the various dialogs - mean the condition is not true. - */ + return -2; /* Error */ } -#endif /* MS_WINDOWS */ - if (feof(fp)) { - return -1; /* EOF */ - } -#ifdef EINTR - if (errno == EINTR) { - int s; -#ifdef WITH_THREAD - PyEval_RestoreThread(_PyOS_ReadlineTState); -#endif - s = PyErr_CheckSignals(); -#ifdef WITH_THREAD - PyEval_SaveThread(); -#endif - if (s < 0) { - return 1; - } - } -#endif - if (PyOS_InterruptOccurred()) { - return 1; /* Interrupt */ - } - return -2; /* Error */ + /* NOTREACHED */ } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 9 20:42:00 2011 From: python-checkins at python.org (ross.lagerwall) Date: Sat, 09 Apr 2011 20:42:00 +0200 Subject: [Python-checkins] cpython (3.1): Issue #11719: Fix message about unexpected test_msilib skip. Message-ID: http://hg.python.org/cpython/rev/d4730f14b6c0 changeset: 69214:d4730f14b6c0 branch: 3.1 parent: 69210:2222f343ac51 user: Ross Lagerwall date: Sat Apr 09 19:30:03 2011 +0200 summary: Issue #11719: Fix message about unexpected test_msilib skip. Patch by Nadeem Vawda. files: Lib/test/regrtest.py | 2 +- Misc/NEWS | 3 +++ 2 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -1239,7 +1239,7 @@ # is distributed with Python WIN_ONLY = ["test_unicode_file", "test_winreg", "test_winsound", "test_startfile", - "test_sqlite"] + "test_sqlite", "test_msilib"] for skip in WIN_ONLY: self.expected.add(skip) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -285,6 +285,9 @@ Tests ----- +- Issue #11719: Fix message about unexpected test_msilib skip on non-Windows + platforms. Patch by Nadeem Vawda. + - Issue #11490: test_subprocess:test_leaking_fds_on_error no longer gives a false positive if the last directory in the path is inaccessible. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 9 20:42:00 2011 From: python-checkins at python.org (ross.lagerwall) Date: Sat, 09 Apr 2011 20:42:00 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): Merge with 3.1 Message-ID: http://hg.python.org/cpython/rev/677e9a9beac2 changeset: 69215:677e9a9beac2 branch: 3.2 parent: 69211:fc2f251e660a parent: 69214:d4730f14b6c0 user: Ross Lagerwall date: Sat Apr 09 20:05:04 2011 +0200 summary: Merge with 3.1 files: Lib/test/regrtest.py | 2 +- Misc/NEWS | 3 +++ 2 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -1480,7 +1480,7 @@ # is distributed with Python WIN_ONLY = {"test_unicode_file", "test_winreg", "test_winsound", "test_startfile", - "test_sqlite"} + "test_sqlite", "test_msilib"} self.expected |= WIN_ONLY if sys.platform != 'sunos5': diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -223,6 +223,9 @@ Tests ----- +- Issue #11719: Fix message about unexpected test_msilib skip on non-Windows + platforms. Patch by Nadeem Vawda. + - Issue #11653: fix -W with -j in regrtest. - Issue #11577: improve test coverage of binhex.py. Patch by Arkady Koplyarov. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 9 20:42:01 2011 From: python-checkins at python.org (ross.lagerwall) Date: Sat, 09 Apr 2011 20:42:01 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge with 3.2 Message-ID: http://hg.python.org/cpython/rev/cdffe73e3218 changeset: 69216:cdffe73e3218 parent: 69212:64de1ded0744 parent: 69215:677e9a9beac2 user: Ross Lagerwall date: Sat Apr 09 20:12:43 2011 +0200 summary: Merge with 3.2 files: Lib/test/regrtest.py | 2 +- Misc/NEWS | 3 +++ 2 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -1530,7 +1530,7 @@ # is distributed with Python WIN_ONLY = {"test_unicode_file", "test_winreg", "test_winsound", "test_startfile", - "test_sqlite"} + "test_sqlite", "test_msilib"} self.expected |= WIN_ONLY if sys.platform != 'sunos5': diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -403,6 +403,9 @@ Tests ----- +- Issue #11719: Fix message about unexpected test_msilib skip on non-Windows + platforms. Patch by Nadeem Vawda. + - Issue #11727: Add a --timeout option to regrtest: if a test takes more than TIMEOUT seconds, dumps the traceback of all threads and exits. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 9 20:42:08 2011 From: python-checkins at python.org (ross.lagerwall) Date: Sat, 09 Apr 2011 20:42:08 +0200 Subject: [Python-checkins] cpython (2.7): Issue #11719: Fix message about unexpected test_msilib skip. Message-ID: http://hg.python.org/cpython/rev/8b146103d29e changeset: 69217:8b146103d29e branch: 2.7 parent: 69213:7febd5ef7619 user: Ross Lagerwall date: Sat Apr 09 20:39:50 2011 +0200 summary: Issue #11719: Fix message about unexpected test_msilib skip. Patch by Nadeem Vawda. files: Lib/test/regrtest.py | 2 +- Misc/NEWS | 3 +++ 2 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -1470,7 +1470,7 @@ # is distributed with Python WIN_ONLY = ["test_unicode_file", "test_winreg", "test_winsound", "test_startfile", - "test_sqlite"] + "test_sqlite", "test_msilib"] for skip in WIN_ONLY: self.expected.add(skip) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -319,6 +319,9 @@ Tests ----- +- Issue #11719: Fix message about unexpected test_msilib skip on non-Windows + platforms. Patch by Nadeem Vawda. + - Issue #7108: Fix test_commands to not fail when special attributes ('@' or '.') appear in 'ls -l' output. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 9 21:48:29 2011 From: python-checkins at python.org (ned.deily) Date: Sat, 09 Apr 2011 21:48:29 +0200 Subject: [Python-checkins] cpython (2.7): Issue #9670: Increase the default stack size for secondary threads on Message-ID: http://hg.python.org/cpython/rev/b0d2b696da19 changeset: 69218:b0d2b696da19 branch: 2.7 user: Ned Deily date: Sat Apr 09 12:29:58 2011 -0700 summary: Issue #9670: Increase the default stack size for secondary threads on Mac OS X and FreeBSD to reduce the chances of a crash instead of a "maximum recursion depth" RuntimeError exception. (Patch by Ronald Oussoren) files: Lib/test/test_threading.py | 30 ++++++++++++++++++++++++++ Misc/NEWS | 5 ++++ Python/thread_pthread.h | 12 ++++++++++ 3 files changed, 47 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py --- a/Lib/test/test_threading.py +++ b/Lib/test/test_threading.py @@ -666,6 +666,36 @@ thread.start() self.assertRaises(RuntimeError, setattr, thread, "daemon", True) + def test_recursion_limit(self): + # Issue 9670 + # test that excessive recursion within a non-main thread causes + # an exception rather than crashing the interpreter on platforms + # like Mac OS X or FreeBSD which have small default stack sizes + # for threads + script = """if True: + import threading + + def recurse(): + return recurse() + + def outer(): + try: + recurse() + except RuntimeError: + pass + + w = threading.Thread(target=outer) + w.start() + w.join() + print('end of main thread') + """ + expected_output = "end of main thread\n" + p = subprocess.Popen([sys.executable, "-c", script], + stdout=subprocess.PIPE) + stdout, stderr = p.communicate() + data = stdout.decode().replace('\r', '') + self.assertEqual(p.returncode, 0, "Unexpected error") + self.assertEqual(data, expected_output) class LockTests(lock_tests.LockTests): locktype = staticmethod(threading.Lock) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -9,6 +9,11 @@ Core and Builtins ----------------- +- Issue #9670: Increase the default stack size for secondary threads on + Mac OS X and FreeBSD to reduce the chances of a crash instead of a + "maximum recursion depth" RuntimeError exception. + (original patch by Ronald Oussoren) + - Issue #11650: PyOS_StdioReadline() retries fgets() if it was interrupted (EINTR), for example if the program is stopped with CTRL+z on Mac OS X. Patch written by Charles-Francois Natali. diff --git a/Python/thread_pthread.h b/Python/thread_pthread.h --- a/Python/thread_pthread.h +++ b/Python/thread_pthread.h @@ -18,6 +18,18 @@ #ifndef THREAD_STACK_SIZE #define THREAD_STACK_SIZE 0 /* use default stack size */ #endif + +#if (defined(__APPLE__) || defined(__FreeBSD__)) && defined(THREAD_STACK_SIZE) && THREAD_STACK_SIZE == 0 + /* The default stack size for new threads on OSX is small enough that + * we'll get hard crashes instead of 'maximum recursion depth exceeded' + * exceptions. + * + * The default stack size below is the minimal stack size where a + * simple recursive function doesn't cause a hard crash. + */ +#undef THREAD_STACK_SIZE +#define THREAD_STACK_SIZE 0x100000 +#endif /* for safety, ensure a viable minimum stacksize */ #define THREAD_STACK_MIN 0x8000 /* 32kB */ #else /* !_POSIX_THREAD_ATTR_STACKSIZE */ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 9 21:48:30 2011 From: python-checkins at python.org (ned.deily) Date: Sat, 09 Apr 2011 21:48:30 +0200 Subject: [Python-checkins] cpython (3.1): Issue #9670: Increase the default stack size for secondary threads on Message-ID: http://hg.python.org/cpython/rev/378b40d71175 changeset: 69219:378b40d71175 branch: 3.1 parent: 69214:d4730f14b6c0 user: Ned Deily date: Sat Apr 09 12:32:12 2011 -0700 summary: Issue #9670: Increase the default stack size for secondary threads on Mac OS X and FreeBSD to reduce the chances of a crash instead of a "maximum recursion depth" RuntimeError exception. (Patch by Ronald Oussoren) files: Lib/test/test_threading.py | 30 ++++++++++++++++++++++++++ Misc/NEWS | 5 ++++ Python/thread_pthread.h | 12 ++++++++++ 3 files changed, 47 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py --- a/Lib/test/test_threading.py +++ b/Lib/test/test_threading.py @@ -650,6 +650,36 @@ thread.start() self.assertRaises(RuntimeError, setattr, thread, "daemon", True) + def test_recursion_limit(self): + # Issue 9670 + # test that excessive recursion within a non-main thread causes + # an exception rather than crashing the interpreter on platforms + # like Mac OS X or FreeBSD which have small default stack sizes + # for threads + script = """if True: + import threading + + def recurse(): + return recurse() + + def outer(): + try: + recurse() + except RuntimeError: + pass + + w = threading.Thread(target=outer) + w.start() + w.join() + print('end of main thread') + """ + expected_output = "end of main thread\n" + p = subprocess.Popen([sys.executable, "-c", script], + stdout=subprocess.PIPE) + stdout, stderr = p.communicate() + data = stdout.decode().replace('\r', '') + self.assertEqual(p.returncode, 0, "Unexpected error") + self.assertEqual(data, expected_output) class LockTests(lock_tests.LockTests): locktype = staticmethod(threading.Lock) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,11 @@ Core and Builtins ----------------- +- Issue #9670: Increase the default stack size for secondary threads on + Mac OS X and FreeBSD to reduce the chances of a crash instead of a + "maximum recursion depth" RuntimeError exception. + (original patch by Ronald Oussoren) + - Issue #11650: PyOS_StdioReadline() retries fgets() if it was interrupted (EINTR), for example if the program is stopped with CTRL+z on Mac OS X. Patch written by Charles-Francois Natali. diff --git a/Python/thread_pthread.h b/Python/thread_pthread.h --- a/Python/thread_pthread.h +++ b/Python/thread_pthread.h @@ -18,6 +18,18 @@ #ifndef THREAD_STACK_SIZE #define THREAD_STACK_SIZE 0 /* use default stack size */ #endif + +#if (defined(__APPLE__) || defined(__FreeBSD__)) && defined(THREAD_STACK_SIZE) && THREAD_STACK_SIZE == 0 + /* The default stack size for new threads on OSX is small enough that + * we'll get hard crashes instead of 'maximum recursion depth exceeded' + * exceptions. + * + * The default stack size below is the minimal stack size where a + * simple recursive function doesn't cause a hard crash. + */ +#undef THREAD_STACK_SIZE +#define THREAD_STACK_SIZE 0x100000 +#endif /* for safety, ensure a viable minimum stacksize */ #define THREAD_STACK_MIN 0x8000 /* 32kB */ #else /* !_POSIX_THREAD_ATTR_STACKSIZE */ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 9 21:48:31 2011 From: python-checkins at python.org (ned.deily) Date: Sat, 09 Apr 2011 21:48:31 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): Issue #9670: merge with 3.2 Message-ID: http://hg.python.org/cpython/rev/3fe8fd2fd1d0 changeset: 69220:3fe8fd2fd1d0 branch: 3.2 parent: 69215:677e9a9beac2 parent: 69219:378b40d71175 user: Ned Deily date: Sat Apr 09 12:37:55 2011 -0700 summary: Issue #9670: merge with 3.2 files: Lib/test/test_threading.py | 30 ++++++++++++++++++++++++++ Misc/NEWS | 5 ++++ Python/thread_pthread.h | 12 ++++++++++ 3 files changed, 47 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py --- a/Lib/test/test_threading.py +++ b/Lib/test/test_threading.py @@ -677,6 +677,36 @@ thread.start() self.assertRaises(RuntimeError, setattr, thread, "daemon", True) + def test_recursion_limit(self): + # Issue 9670 + # test that excessive recursion within a non-main thread causes + # an exception rather than crashing the interpreter on platforms + # like Mac OS X or FreeBSD which have small default stack sizes + # for threads + script = """if True: + import threading + + def recurse(): + return recurse() + + def outer(): + try: + recurse() + except RuntimeError: + pass + + w = threading.Thread(target=outer) + w.start() + w.join() + print('end of main thread') + """ + expected_output = "end of main thread\n" + p = subprocess.Popen([sys.executable, "-c", script], + stdout=subprocess.PIPE) + stdout, stderr = p.communicate() + data = stdout.decode().replace('\r', '') + self.assertEqual(p.returncode, 0, "Unexpected error") + self.assertEqual(data, expected_output) class LockTests(lock_tests.LockTests): locktype = staticmethod(threading.Lock) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,11 @@ Core and Builtins ----------------- +- Issue #9670: Increase the default stack size for secondary threads on + Mac OS X and FreeBSD to reduce the chances of a crash instead of a + "maximum recursion depth" RuntimeError exception. + (original patch by Ronald Oussoren) + - Issue #11650: PyOS_StdioReadline() retries fgets() if it was interrupted (EINTR), for example if the program is stopped with CTRL+z on Mac OS X. Patch written by Charles-Francois Natali. diff --git a/Python/thread_pthread.h b/Python/thread_pthread.h --- a/Python/thread_pthread.h +++ b/Python/thread_pthread.h @@ -18,6 +18,18 @@ #ifndef THREAD_STACK_SIZE #define THREAD_STACK_SIZE 0 /* use default stack size */ #endif + +#if (defined(__APPLE__) || defined(__FreeBSD__)) && defined(THREAD_STACK_SIZE) && THREAD_STACK_SIZE == 0 + /* The default stack size for new threads on OSX is small enough that + * we'll get hard crashes instead of 'maximum recursion depth exceeded' + * exceptions. + * + * The default stack size below is the minimal stack size where a + * simple recursive function doesn't cause a hard crash. + */ +#undef THREAD_STACK_SIZE +#define THREAD_STACK_SIZE 0x100000 +#endif /* for safety, ensure a viable minimum stacksize */ #define THREAD_STACK_MIN 0x8000 /* 32kB */ #else /* !_POSIX_THREAD_ATTR_STACKSIZE */ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 9 21:48:36 2011 From: python-checkins at python.org (ned.deily) Date: Sat, 09 Apr 2011 21:48:36 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Issue #9670: merge with current Message-ID: http://hg.python.org/cpython/rev/4c750091d8c5 changeset: 69221:4c750091d8c5 parent: 69216:cdffe73e3218 parent: 69220:3fe8fd2fd1d0 user: Ned Deily date: Sat Apr 09 12:47:12 2011 -0700 summary: Issue #9670: merge with current files: Lib/test/test_threading.py | 30 ++++++++++++++++++++++++++ Misc/NEWS | 5 ++++ Python/thread_pthread.h | 12 ++++++++++ 3 files changed, 47 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py --- a/Lib/test/test_threading.py +++ b/Lib/test/test_threading.py @@ -689,6 +689,36 @@ lock = threading.Lock() self.assertRaises(RuntimeError, lock.release) + def test_recursion_limit(self): + # Issue 9670 + # test that excessive recursion within a non-main thread causes + # an exception rather than crashing the interpreter on platforms + # like Mac OS X or FreeBSD which have small default stack sizes + # for threads + script = """if True: + import threading + + def recurse(): + return recurse() + + def outer(): + try: + recurse() + except RuntimeError: + pass + + w = threading.Thread(target=outer) + w.start() + w.join() + print('end of main thread') + """ + expected_output = "end of main thread\n" + p = subprocess.Popen([sys.executable, "-c", script], + stdout=subprocess.PIPE) + stdout, stderr = p.communicate() + data = stdout.decode().replace('\r', '') + self.assertEqual(p.returncode, 0, "Unexpected error") + self.assertEqual(data, expected_output) class LockTests(lock_tests.LockTests): locktype = staticmethod(threading.Lock) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,11 @@ Core and Builtins ----------------- +- Issue #9670: Increase the default stack size for secondary threads on + Mac OS X and FreeBSD to reduce the chances of a crash instead of a + "maximum recursion depth" RuntimeError exception. + (original patch by Ronald Oussoren) + - Issue #11650: PyOS_StdioReadline() retries fgets() if it was interrupted (EINTR), for example if the program is stopped with CTRL+z on Mac OS X. Patch written by Charles-Francois Natali. diff --git a/Python/thread_pthread.h b/Python/thread_pthread.h --- a/Python/thread_pthread.h +++ b/Python/thread_pthread.h @@ -18,6 +18,18 @@ #ifndef THREAD_STACK_SIZE #define THREAD_STACK_SIZE 0 /* use default stack size */ #endif + +#if (defined(__APPLE__) || defined(__FreeBSD__)) && defined(THREAD_STACK_SIZE) && THREAD_STACK_SIZE == 0 + /* The default stack size for new threads on OSX is small enough that + * we'll get hard crashes instead of 'maximum recursion depth exceeded' + * exceptions. + * + * The default stack size below is the minimal stack size where a + * simple recursive function doesn't cause a hard crash. + */ +#undef THREAD_STACK_SIZE +#define THREAD_STACK_SIZE 0x100000 +#endif /* for safety, ensure a viable minimum stacksize */ #define THREAD_STACK_MIN 0x8000 /* 32kB */ #else /* !_POSIX_THREAD_ATTR_STACKSIZE */ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 9 22:00:25 2011 From: python-checkins at python.org (raymond.hettinger) Date: Sat, 09 Apr 2011 22:00:25 +0200 Subject: [Python-checkins] cpython: Fix nit (make spelling consistent in prototype) Message-ID: http://hg.python.org/cpython/rev/a593a1030f2c changeset: 69222:a593a1030f2c user: Raymond Hettinger date: Sat Apr 09 12:57:00 2011 -0700 summary: Fix nit (make spelling consistent in prototype) files: Modules/_functoolsmodule.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Modules/_functoolsmodule.c b/Modules/_functoolsmodule.c --- a/Modules/_functoolsmodule.c +++ b/Modules/_functoolsmodule.c @@ -372,7 +372,7 @@ }; static PyObject * -keyobject_call(keyobject *ko, PyObject *args, PyObject *kw); +keyobject_call(keyobject *ko, PyObject *args, PyObject *kwds); static PyObject * keyobject_richcompare(PyObject *ko, PyObject *other, int op); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 9 22:00:25 2011 From: python-checkins at python.org (raymond.hettinger) Date: Sat, 09 Apr 2011 22:00:25 +0200 Subject: [Python-checkins] cpython: Replace constant tuple with constant set. Message-ID: http://hg.python.org/cpython/rev/a1235865dd54 changeset: 69223:a1235865dd54 user: Raymond Hettinger date: Sat Apr 09 13:00:17 2011 -0700 summary: Replace constant tuple with constant set. files: Lib/difflib.py | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/difflib.py b/Lib/difflib.py --- a/Lib/difflib.py +++ b/Lib/difflib.py @@ -1267,7 +1267,7 @@ yield '*** %d,%d ****%s' % (group[0][1]+1, group[-1][2], lineterm) else: yield '*** %d ****%s' % (group[-1][2], lineterm) - visiblechanges = [e for e in group if e[0] in ('replace', 'delete')] + visiblechanges = [e for e in group if e[0] in {'replace', 'delete'}] if visiblechanges: for tag, i1, i2, _, _ in group: if tag != 'insert': @@ -1278,7 +1278,7 @@ yield '--- %d,%d ----%s' % (group[0][3]+1, group[-1][4], lineterm) else: yield '--- %d ----%s' % (group[-1][4], lineterm) - visiblechanges = [e for e in group if e[0] in ('replace', 'insert')] + visiblechanges = [e for e in group if e[0] in {'replace', 'insert'}] if visiblechanges: for tag, _, _, j1, j2 in group: if tag != 'delete': -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 9 23:50:02 2011 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 09 Apr 2011 23:50:02 +0200 Subject: [Python-checkins] cpython: Issue #11757: select.select() now raises ValueError when a negative timeout Message-ID: http://hg.python.org/cpython/rev/3982be773b54 changeset: 69224:3982be773b54 user: Antoine Pitrou date: Sat Apr 09 23:49:58 2011 +0200 summary: Issue #11757: select.select() now raises ValueError when a negative timeout is passed (previously, a select.error with EINVAL would be raised). Patch by Charles-Fran?ois Natali. files: Lib/test/test_select.py | 1 + Misc/NEWS | 4 ++++ Modules/selectmodule.c | 5 +++++ 3 files changed, 10 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_select.py b/Lib/test/test_select.py --- a/Lib/test/test_select.py +++ b/Lib/test/test_select.py @@ -20,6 +20,7 @@ self.assertRaises(TypeError, select.select, [self.Nope()], [], []) self.assertRaises(TypeError, select.select, [self.Almost()], [], []) self.assertRaises(TypeError, select.select, [], [], [], "not a number") + self.assertRaises(ValueError, select.select, [], [], [], -1) def test_returned_list_identity(self): # See issue #8329 diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -103,6 +103,10 @@ Library ------- +- Issue #11757: select.select() now raises ValueError when a negative timeout + is passed (previously, a select.error with EINVAL would be raised). Patch + by Charles-Fran?ois Natali. + - Issue #7311: fix html.parser to accept non-ASCII attribute values. - Issue #11605: email.parser.BytesFeedParser was incorrectly converting multipart diff --git a/Modules/selectmodule.c b/Modules/selectmodule.c --- a/Modules/selectmodule.c +++ b/Modules/selectmodule.c @@ -234,6 +234,11 @@ "timeout period too long"); return NULL; } + if (timeout < 0) { + PyErr_SetString(PyExc_ValueError, + "timeout must be non-negative"); + return NULL; + } seconds = (long)timeout; timeout = timeout - (double)seconds; tv.tv_sec = seconds; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Apr 10 00:01:20 2011 From: python-checkins at python.org (ned.deily) Date: Sun, 10 Apr 2011 00:01:20 +0200 Subject: [Python-checkins] cpython (3.1): Issue9670: Back out changeset 378b40d71175; test fails on other platforms Message-ID: http://hg.python.org/cpython/rev/42d5001e5845 changeset: 69225:42d5001e5845 branch: 3.1 parent: 69219:378b40d71175 user: Ned Deily date: Sat Apr 09 14:50:59 2011 -0700 summary: Issue9670: Back out changeset 378b40d71175; test fails on other platforms and on OS X with pydebug. files: Lib/test/test_threading.py | 30 -------------------------- Misc/NEWS | 5 ---- Python/thread_pthread.h | 12 ---------- 3 files changed, 0 insertions(+), 47 deletions(-) diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py --- a/Lib/test/test_threading.py +++ b/Lib/test/test_threading.py @@ -650,36 +650,6 @@ thread.start() self.assertRaises(RuntimeError, setattr, thread, "daemon", True) - def test_recursion_limit(self): - # Issue 9670 - # test that excessive recursion within a non-main thread causes - # an exception rather than crashing the interpreter on platforms - # like Mac OS X or FreeBSD which have small default stack sizes - # for threads - script = """if True: - import threading - - def recurse(): - return recurse() - - def outer(): - try: - recurse() - except RuntimeError: - pass - - w = threading.Thread(target=outer) - w.start() - w.join() - print('end of main thread') - """ - expected_output = "end of main thread\n" - p = subprocess.Popen([sys.executable, "-c", script], - stdout=subprocess.PIPE) - stdout, stderr = p.communicate() - data = stdout.decode().replace('\r', '') - self.assertEqual(p.returncode, 0, "Unexpected error") - self.assertEqual(data, expected_output) class LockTests(lock_tests.LockTests): locktype = staticmethod(threading.Lock) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,11 +10,6 @@ Core and Builtins ----------------- -- Issue #9670: Increase the default stack size for secondary threads on - Mac OS X and FreeBSD to reduce the chances of a crash instead of a - "maximum recursion depth" RuntimeError exception. - (original patch by Ronald Oussoren) - - Issue #11650: PyOS_StdioReadline() retries fgets() if it was interrupted (EINTR), for example if the program is stopped with CTRL+z on Mac OS X. Patch written by Charles-Francois Natali. diff --git a/Python/thread_pthread.h b/Python/thread_pthread.h --- a/Python/thread_pthread.h +++ b/Python/thread_pthread.h @@ -18,18 +18,6 @@ #ifndef THREAD_STACK_SIZE #define THREAD_STACK_SIZE 0 /* use default stack size */ #endif - -#if (defined(__APPLE__) || defined(__FreeBSD__)) && defined(THREAD_STACK_SIZE) && THREAD_STACK_SIZE == 0 - /* The default stack size for new threads on OSX is small enough that - * we'll get hard crashes instead of 'maximum recursion depth exceeded' - * exceptions. - * - * The default stack size below is the minimal stack size where a - * simple recursive function doesn't cause a hard crash. - */ -#undef THREAD_STACK_SIZE -#define THREAD_STACK_SIZE 0x100000 -#endif /* for safety, ensure a viable minimum stacksize */ #define THREAD_STACK_MIN 0x8000 /* 32kB */ #else /* !_POSIX_THREAD_ATTR_STACKSIZE */ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Apr 10 00:01:21 2011 From: python-checkins at python.org (ned.deily) Date: Sun, 10 Apr 2011 00:01:21 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): Issue9670: Merge backout to 3.2. Message-ID: http://hg.python.org/cpython/rev/54edabf2846d changeset: 69226:54edabf2846d branch: 3.2 parent: 69220:3fe8fd2fd1d0 parent: 69225:42d5001e5845 user: Ned Deily date: Sat Apr 09 14:53:47 2011 -0700 summary: Issue9670: Merge backout to 3.2. files: Lib/test/test_threading.py | 30 -------------------------- Misc/NEWS | 5 ---- Python/thread_pthread.h | 12 ---------- 3 files changed, 0 insertions(+), 47 deletions(-) diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py --- a/Lib/test/test_threading.py +++ b/Lib/test/test_threading.py @@ -677,36 +677,6 @@ thread.start() self.assertRaises(RuntimeError, setattr, thread, "daemon", True) - def test_recursion_limit(self): - # Issue 9670 - # test that excessive recursion within a non-main thread causes - # an exception rather than crashing the interpreter on platforms - # like Mac OS X or FreeBSD which have small default stack sizes - # for threads - script = """if True: - import threading - - def recurse(): - return recurse() - - def outer(): - try: - recurse() - except RuntimeError: - pass - - w = threading.Thread(target=outer) - w.start() - w.join() - print('end of main thread') - """ - expected_output = "end of main thread\n" - p = subprocess.Popen([sys.executable, "-c", script], - stdout=subprocess.PIPE) - stdout, stderr = p.communicate() - data = stdout.decode().replace('\r', '') - self.assertEqual(p.returncode, 0, "Unexpected error") - self.assertEqual(data, expected_output) class LockTests(lock_tests.LockTests): locktype = staticmethod(threading.Lock) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,11 +10,6 @@ Core and Builtins ----------------- -- Issue #9670: Increase the default stack size for secondary threads on - Mac OS X and FreeBSD to reduce the chances of a crash instead of a - "maximum recursion depth" RuntimeError exception. - (original patch by Ronald Oussoren) - - Issue #11650: PyOS_StdioReadline() retries fgets() if it was interrupted (EINTR), for example if the program is stopped with CTRL+z on Mac OS X. Patch written by Charles-Francois Natali. diff --git a/Python/thread_pthread.h b/Python/thread_pthread.h --- a/Python/thread_pthread.h +++ b/Python/thread_pthread.h @@ -18,18 +18,6 @@ #ifndef THREAD_STACK_SIZE #define THREAD_STACK_SIZE 0 /* use default stack size */ #endif - -#if (defined(__APPLE__) || defined(__FreeBSD__)) && defined(THREAD_STACK_SIZE) && THREAD_STACK_SIZE == 0 - /* The default stack size for new threads on OSX is small enough that - * we'll get hard crashes instead of 'maximum recursion depth exceeded' - * exceptions. - * - * The default stack size below is the minimal stack size where a - * simple recursive function doesn't cause a hard crash. - */ -#undef THREAD_STACK_SIZE -#define THREAD_STACK_SIZE 0x100000 -#endif /* for safety, ensure a viable minimum stacksize */ #define THREAD_STACK_MIN 0x8000 /* 32kB */ #else /* !_POSIX_THREAD_ATTR_STACKSIZE */ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Apr 10 00:01:26 2011 From: python-checkins at python.org (ned.deily) Date: Sun, 10 Apr 2011 00:01:26 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Issue9670: Merge backout from 3.2. Message-ID: http://hg.python.org/cpython/rev/b7456c1b4aa4 changeset: 69227:b7456c1b4aa4 parent: 69224:3982be773b54 parent: 69226:54edabf2846d user: Ned Deily date: Sat Apr 09 14:58:04 2011 -0700 summary: Issue9670: Merge backout from 3.2. files: Lib/test/test_threading.py | 30 -------------------------- Misc/NEWS | 5 ---- Python/thread_pthread.h | 12 ---------- 3 files changed, 0 insertions(+), 47 deletions(-) diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py --- a/Lib/test/test_threading.py +++ b/Lib/test/test_threading.py @@ -689,36 +689,6 @@ lock = threading.Lock() self.assertRaises(RuntimeError, lock.release) - def test_recursion_limit(self): - # Issue 9670 - # test that excessive recursion within a non-main thread causes - # an exception rather than crashing the interpreter on platforms - # like Mac OS X or FreeBSD which have small default stack sizes - # for threads - script = """if True: - import threading - - def recurse(): - return recurse() - - def outer(): - try: - recurse() - except RuntimeError: - pass - - w = threading.Thread(target=outer) - w.start() - w.join() - print('end of main thread') - """ - expected_output = "end of main thread\n" - p = subprocess.Popen([sys.executable, "-c", script], - stdout=subprocess.PIPE) - stdout, stderr = p.communicate() - data = stdout.decode().replace('\r', '') - self.assertEqual(p.returncode, 0, "Unexpected error") - self.assertEqual(data, expected_output) class LockTests(lock_tests.LockTests): locktype = staticmethod(threading.Lock) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,11 +10,6 @@ Core and Builtins ----------------- -- Issue #9670: Increase the default stack size for secondary threads on - Mac OS X and FreeBSD to reduce the chances of a crash instead of a - "maximum recursion depth" RuntimeError exception. - (original patch by Ronald Oussoren) - - Issue #11650: PyOS_StdioReadline() retries fgets() if it was interrupted (EINTR), for example if the program is stopped with CTRL+z on Mac OS X. Patch written by Charles-Francois Natali. diff --git a/Python/thread_pthread.h b/Python/thread_pthread.h --- a/Python/thread_pthread.h +++ b/Python/thread_pthread.h @@ -18,18 +18,6 @@ #ifndef THREAD_STACK_SIZE #define THREAD_STACK_SIZE 0 /* use default stack size */ #endif - -#if (defined(__APPLE__) || defined(__FreeBSD__)) && defined(THREAD_STACK_SIZE) && THREAD_STACK_SIZE == 0 - /* The default stack size for new threads on OSX is small enough that - * we'll get hard crashes instead of 'maximum recursion depth exceeded' - * exceptions. - * - * The default stack size below is the minimal stack size where a - * simple recursive function doesn't cause a hard crash. - */ -#undef THREAD_STACK_SIZE -#define THREAD_STACK_SIZE 0x100000 -#endif /* for safety, ensure a viable minimum stacksize */ #define THREAD_STACK_MIN 0x8000 /* 32kB */ #else /* !_POSIX_THREAD_ATTR_STACKSIZE */ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Apr 10 00:01:27 2011 From: python-checkins at python.org (ned.deily) Date: Sun, 10 Apr 2011 00:01:27 +0200 Subject: [Python-checkins] cpython (2.7): Issue9670: Back out changeset b0d2b696da19; test fails on other platforms Message-ID: http://hg.python.org/cpython/rev/3630bc3d5a88 changeset: 69228:3630bc3d5a88 branch: 2.7 parent: 69218:b0d2b696da19 user: Ned Deily date: Sat Apr 09 14:59:30 2011 -0700 summary: Issue9670: Back out changeset b0d2b696da19; test fails on other platforms and on OS X with pydebug. files: Lib/test/test_threading.py | 30 -------------------------- Misc/NEWS | 5 ---- Python/thread_pthread.h | 12 ---------- 3 files changed, 0 insertions(+), 47 deletions(-) diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py --- a/Lib/test/test_threading.py +++ b/Lib/test/test_threading.py @@ -666,36 +666,6 @@ thread.start() self.assertRaises(RuntimeError, setattr, thread, "daemon", True) - def test_recursion_limit(self): - # Issue 9670 - # test that excessive recursion within a non-main thread causes - # an exception rather than crashing the interpreter on platforms - # like Mac OS X or FreeBSD which have small default stack sizes - # for threads - script = """if True: - import threading - - def recurse(): - return recurse() - - def outer(): - try: - recurse() - except RuntimeError: - pass - - w = threading.Thread(target=outer) - w.start() - w.join() - print('end of main thread') - """ - expected_output = "end of main thread\n" - p = subprocess.Popen([sys.executable, "-c", script], - stdout=subprocess.PIPE) - stdout, stderr = p.communicate() - data = stdout.decode().replace('\r', '') - self.assertEqual(p.returncode, 0, "Unexpected error") - self.assertEqual(data, expected_output) class LockTests(lock_tests.LockTests): locktype = staticmethod(threading.Lock) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -9,11 +9,6 @@ Core and Builtins ----------------- -- Issue #9670: Increase the default stack size for secondary threads on - Mac OS X and FreeBSD to reduce the chances of a crash instead of a - "maximum recursion depth" RuntimeError exception. - (original patch by Ronald Oussoren) - - Issue #11650: PyOS_StdioReadline() retries fgets() if it was interrupted (EINTR), for example if the program is stopped with CTRL+z on Mac OS X. Patch written by Charles-Francois Natali. diff --git a/Python/thread_pthread.h b/Python/thread_pthread.h --- a/Python/thread_pthread.h +++ b/Python/thread_pthread.h @@ -18,18 +18,6 @@ #ifndef THREAD_STACK_SIZE #define THREAD_STACK_SIZE 0 /* use default stack size */ #endif - -#if (defined(__APPLE__) || defined(__FreeBSD__)) && defined(THREAD_STACK_SIZE) && THREAD_STACK_SIZE == 0 - /* The default stack size for new threads on OSX is small enough that - * we'll get hard crashes instead of 'maximum recursion depth exceeded' - * exceptions. - * - * The default stack size below is the minimal stack size where a - * simple recursive function doesn't cause a hard crash. - */ -#undef THREAD_STACK_SIZE -#define THREAD_STACK_SIZE 0x100000 -#endif /* for safety, ensure a viable minimum stacksize */ #define THREAD_STACK_MIN 0x8000 /* 32kB */ #else /* !_POSIX_THREAD_ATTR_STACKSIZE */ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Apr 10 04:41:47 2011 From: python-checkins at python.org (raymond.hettinger) Date: Sun, 10 Apr 2011 04:41:47 +0200 Subject: [Python-checkins] cpython (3.2): Beautify and modernize the SequenceMatcher example Message-ID: http://hg.python.org/cpython/rev/35f4e0d1d64b changeset: 69229:35f4e0d1d64b branch: 3.2 parent: 69226:54edabf2846d user: Raymond Hettinger date: Sat Apr 09 19:41:00 2011 -0700 summary: Beautify and modernize the SequenceMatcher example files: Doc/library/difflib.rst | 16 +++++++++------- 1 files changed, 9 insertions(+), 7 deletions(-) diff --git a/Doc/library/difflib.rst b/Doc/library/difflib.rst --- a/Doc/library/difflib.rst +++ b/Doc/library/difflib.rst @@ -483,13 +483,15 @@ >>> b = "abycdf" >>> s = SequenceMatcher(None, a, b) >>> for tag, i1, i2, j1, j2 in s.get_opcodes(): - ... print(("%7s a[%d:%d] (%s) b[%d:%d] (%s)" % - ... (tag, i1, i2, a[i1:i2], j1, j2, b[j1:j2]))) - delete a[0:1] (q) b[0:0] () - equal a[1:3] (ab) b[0:2] (ab) - replace a[3:4] (x) b[2:3] (y) - equal a[4:6] (cd) b[3:5] (cd) - insert a[6:6] () b[5:6] (f) + print('{:7} a[{}:{}] --> b[{}:{}] {!r:>8} --> {!r}'.format( + tag, i1, i2, j1, j2, a[i1:i2], b[j1:j2])) + + + delete a[0:1] --> b[0:0] 'q' --> '' + equal a[1:3] --> b[0:2] 'ab' --> 'ab' + replace a[3:4] --> b[2:3] 'x' --> 'y' + equal a[4:6] --> b[3:5] 'cd' --> 'cd' + insert a[6:6] --> b[5:6] '' --> 'f' .. method:: get_grouped_opcodes(n=3) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Apr 10 04:41:48 2011 From: python-checkins at python.org (raymond.hettinger) Date: Sun, 10 Apr 2011 04:41:48 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Beautify and modernize the SequenceMatcher example Message-ID: http://hg.python.org/cpython/rev/aff9bcbd2fc7 changeset: 69230:aff9bcbd2fc7 parent: 69227:b7456c1b4aa4 parent: 69229:35f4e0d1d64b user: Raymond Hettinger date: Sat Apr 09 19:41:31 2011 -0700 summary: Beautify and modernize the SequenceMatcher example files: Doc/library/difflib.rst | 16 +++++++++------- 1 files changed, 9 insertions(+), 7 deletions(-) diff --git a/Doc/library/difflib.rst b/Doc/library/difflib.rst --- a/Doc/library/difflib.rst +++ b/Doc/library/difflib.rst @@ -483,13 +483,15 @@ >>> b = "abycdf" >>> s = SequenceMatcher(None, a, b) >>> for tag, i1, i2, j1, j2 in s.get_opcodes(): - ... print(("%7s a[%d:%d] (%s) b[%d:%d] (%s)" % - ... (tag, i1, i2, a[i1:i2], j1, j2, b[j1:j2]))) - delete a[0:1] (q) b[0:0] () - equal a[1:3] (ab) b[0:2] (ab) - replace a[3:4] (x) b[2:3] (y) - equal a[4:6] (cd) b[3:5] (cd) - insert a[6:6] () b[5:6] (f) + print('{:7} a[{}:{}] --> b[{}:{}] {!r:>8} --> {!r}'.format( + tag, i1, i2, j1, j2, a[i1:i2], b[j1:j2])) + + + delete a[0:1] --> b[0:0] 'q' --> '' + equal a[1:3] --> b[0:2] 'ab' --> 'ab' + replace a[3:4] --> b[2:3] 'x' --> 'y' + equal a[4:6] --> b[3:5] 'cd' --> 'cd' + insert a[6:6] --> b[5:6] '' --> 'f' .. method:: get_grouped_opcodes(n=3) -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Sun Apr 10 04:56:54 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sun, 10 Apr 2011 04:56:54 +0200 Subject: [Python-checkins] Daily reference leaks (b7456c1b4aa4): sum=0 Message-ID: results for b7456c1b4aa4 on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogS4QsUQ', '-x'] From python-checkins at python.org Sun Apr 10 06:33:06 2011 From: python-checkins at python.org (eli.bendersky) Date: Sun, 10 Apr 2011 06:33:06 +0200 Subject: [Python-checkins] cpython: Issue #9904: fix and clarify some comments + fix indentation in symtable code Message-ID: http://hg.python.org/cpython/rev/b6fe63c914e4 changeset: 69231:b6fe63c914e4 user: Eli Bendersky date: Sun Apr 10 07:37:26 2011 +0300 summary: Issue #9904: fix and clarify some comments + fix indentation in symtable code files: Include/symtable.h | 11 +++++++---- Python/symtable.c | 8 ++++---- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/Include/symtable.h b/Include/symtable.h --- a/Include/symtable.h +++ b/Include/symtable.h @@ -23,10 +23,13 @@ PyObject *st_blocks; /* dict: map AST node addresses * to symbol table entries */ PyObject *st_stack; /* list: stack of namespace info */ - PyObject *st_global; /* borrowed ref to st_top->st_symbols */ - int st_nblocks; /* number of blocks used */ + PyObject *st_global; /* borrowed ref to st_top->ste_symbols */ + int st_nblocks; /* number of blocks used. kept for + consistency with the corresponding + compiler structure */ PyObject *st_private; /* name of current class or NULL */ - PyFutureFeatures *st_future; /* module's future features */ + PyFutureFeatures *st_future; /* module's future features that affect + the symbol table */ }; typedef struct _symtable_entry { @@ -34,7 +37,7 @@ PyObject *ste_id; /* int: key in ste_table->st_blocks */ PyObject *ste_symbols; /* dict: variable names to flags */ PyObject *ste_name; /* string: name of current block */ - PyObject *ste_varnames; /* list of variable names */ + PyObject *ste_varnames; /* list of function parameters */ PyObject *ste_children; /* list of child blocks */ _Py_block_ty ste_type; /* module, class, or function */ int ste_unoptimized; /* false if namespace is optimized */ diff --git a/Python/symtable.c b/Python/symtable.c --- a/Python/symtable.c +++ b/Python/symtable.c @@ -750,7 +750,7 @@ goto error; } - /* Recursively call analyze_block() on each child block. + /* Recursively call analyze_child_block() on each child block. newbound, newglobal now contain the names visible in nested blocks. The free variables in the children will @@ -1205,9 +1205,9 @@ case Raise_kind: if (s->v.Raise.exc) { VISIT(st, expr, s->v.Raise.exc); - if (s->v.Raise.cause) { - VISIT(st, expr, s->v.Raise.cause); - } + if (s->v.Raise.cause) { + VISIT(st, expr, s->v.Raise.cause); + } } break; case TryExcept_kind: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Apr 10 08:20:15 2011 From: python-checkins at python.org (georg.brandl) Date: Sun, 10 Apr 2011 08:20:15 +0200 Subject: [Python-checkins] devguide: Add Nadeem. Message-ID: http://hg.python.org/devguide/rev/aff894ab4c20 changeset: 411:aff894ab4c20 user: Georg Brandl date: Sun Apr 10 08:20:13 2011 +0200 summary: Add Nadeem. files: developers.rst | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/developers.rst b/developers.rst --- a/developers.rst +++ b/developers.rst @@ -24,6 +24,9 @@ Permissions History ------------------- +- Nadeem Vawda was given push privileges on Apr 10 2011 by GFB, for + general contributions, on recommendation by Antoine Pitrou. + - Carl Friedrich Bolz was given push privileges on Mar 21 2011 by BAC, for stdlib compatibility work for PyPy. -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Sun Apr 10 09:03:17 2011 From: python-checkins at python.org (georg.brandl) Date: Sun, 10 Apr 2011 09:03:17 +0200 Subject: [Python-checkins] devguide: Update address for sending SSH keys to. Message-ID: http://hg.python.org/devguide/rev/56b895308730 changeset: 412:56b895308730 user: Georg Brandl date: Sun Apr 10 09:03:14 2011 +0200 summary: Update address for sending SSH keys to. files: coredev.rst | 2 +- faq.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/coredev.rst b/coredev.rst --- a/coredev.rst +++ b/coredev.rst @@ -60,7 +60,7 @@ You need to generate an SSH 2 RSA key to be able to commit code. You may have multiple keys if you wish (e.g., for work and home). Send your key as an -attachment in an email to python-committers at python.org (do not paste it in +attachment in an email to hgaccounts at python.org (do not paste it in the email as SSH keys have specific formatting requirements). Help in generating an SSH key can be found in the :ref:`faq`. diff --git a/faq.rst b/faq.rst --- a/faq.rst +++ b/faq.rst @@ -676,7 +676,7 @@ How do I generate an SSH 2 public key? ------------------------------------------------------------------------------- -All generated SSH keys should be sent to python-committers at python.org for +All generated SSH keys should be sent to hgaccounts at python.org for adding to the list of keys. UNIX -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Sun Apr 10 09:41:47 2011 From: python-checkins at python.org (ross.lagerwall) Date: Sun, 10 Apr 2011 09:41:47 +0200 Subject: [Python-checkins] cpython (3.2): Issue #11818: Fix tempfile examples for Python 3. Message-ID: http://hg.python.org/cpython/rev/87d89f767b23 changeset: 69232:87d89f767b23 branch: 3.2 parent: 69229:35f4e0d1d64b user: Ross Lagerwall date: Sun Apr 10 09:30:04 2011 +0200 summary: Issue #11818: Fix tempfile examples for Python 3. files: Doc/library/tempfile.rst | 10 +++++----- Misc/NEWS | 5 +++++ 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/Doc/library/tempfile.rst b/Doc/library/tempfile.rst --- a/Doc/library/tempfile.rst +++ b/Doc/library/tempfile.rst @@ -242,26 +242,26 @@ # create a temporary file and write some data to it >>> fp = tempfile.TemporaryFile() - >>> fp.write('Hello world!') + >>> fp.write(b'Hello world!') # read data from file >>> fp.seek(0) >>> fp.read() - 'Hello world!' + b'Hello world!' # close the file, it will be removed >>> fp.close() # create a temporary file using a context manager >>> with tempfile.TemporaryFile() as fp: - ... fp.write('Hello world!') + ... fp.write(b'Hello world!') ... fp.seek(0) ... fp.read() - 'Hello world!' + b'Hello world!' >>> # file is now closed and removed # create a temporary directory using the context manager >>> with tempfile.TemporaryDirectory() as tmpdirname: - ... print 'created temporary directory', tmpdirname + ... print('created temporary directory', tmpdirname) >>> # directory and contents have been removed diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -257,6 +257,11 @@ - Issue #10826: Prevent sporadic failure in test_subprocess on Solaris due to open door files. +Documentation +------------- + +- Issue #11818: Fix tempfile examples for Python 3. + What's New in Python 3.2? ========================= -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Apr 10 09:41:48 2011 From: python-checkins at python.org (ross.lagerwall) Date: Sun, 10 Apr 2011 09:41:48 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge with 3.2 Message-ID: http://hg.python.org/cpython/rev/655c8849937f changeset: 69233:655c8849937f parent: 69231:b6fe63c914e4 parent: 69232:87d89f767b23 user: Ross Lagerwall date: Sun Apr 10 09:34:35 2011 +0200 summary: Merge with 3.2 files: Doc/library/tempfile.rst | 10 +++++----- Misc/NEWS | 5 +++++ 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/Doc/library/tempfile.rst b/Doc/library/tempfile.rst --- a/Doc/library/tempfile.rst +++ b/Doc/library/tempfile.rst @@ -242,26 +242,26 @@ # create a temporary file and write some data to it >>> fp = tempfile.TemporaryFile() - >>> fp.write('Hello world!') + >>> fp.write(b'Hello world!') # read data from file >>> fp.seek(0) >>> fp.read() - 'Hello world!' + b'Hello world!' # close the file, it will be removed >>> fp.close() # create a temporary file using a context manager >>> with tempfile.TemporaryFile() as fp: - ... fp.write('Hello world!') + ... fp.write(b'Hello world!') ... fp.seek(0) ... fp.read() - 'Hello world!' + b'Hello world!' >>> # file is now closed and removed # create a temporary directory using the context manager >>> with tempfile.TemporaryDirectory() as tmpdirname: - ... print 'created temporary directory', tmpdirname + ... print('created temporary directory', tmpdirname) >>> # directory and contents have been removed diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -466,6 +466,11 @@ - PY_PATCHLEVEL_REVISION has been removed, since it's meaningless with Mercurial. +Documentation +------------- + +- Issue #11818: Fix tempfile examples for Python 3. + What's New in Python 3.2? ========================= -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Apr 10 11:33:19 2011 From: python-checkins at python.org (nadeem.vawda) Date: Sun, 10 Apr 2011 11:33:19 +0200 Subject: [Python-checkins] devguide: Add myself to the Experts Index for bz2. Message-ID: http://hg.python.org/devguide/rev/5a8ced2895c7 changeset: 413:5a8ced2895c7 user: Nadeem Vawda date: Sun Apr 10 11:31:10 2011 +0200 summary: Add myself to the Experts Index for bz2. files: experts.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/experts.rst b/experts.rst --- a/experts.rst +++ b/experts.rst @@ -63,7 +63,7 @@ binhex bisect rhettinger builtins -bz2 +bz2 nadeem.vawda calendar rhettinger cgi cgitb -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Sun Apr 10 11:59:35 2011 From: python-checkins at python.org (ezio.melotti) Date: Sun, 10 Apr 2011 11:59:35 +0200 Subject: [Python-checkins] cpython: #2650: re.escape() no longer escapes the "_". Message-ID: http://hg.python.org/cpython/rev/dda33191f7f5 changeset: 69234:dda33191f7f5 user: Ezio Melotti date: Sun Apr 10 12:59:16 2011 +0300 summary: #2650: re.escape() no longer escapes the "_". files: Doc/library/re.rst | 9 ++++++--- Lib/re.py | 8 +++++--- Lib/test/test_re.py | 4 ++-- Misc/NEWS | 2 ++ 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/Doc/library/re.rst b/Doc/library/re.rst --- a/Doc/library/re.rst +++ b/Doc/library/re.rst @@ -689,9 +689,12 @@ .. function:: escape(string) - Return *string* with all non-alphanumerics backslashed; this is useful if you - want to match an arbitrary literal string that may have regular expression - metacharacters in it. + Escape all the characters in pattern except ASCII letters, numbers and ``'_'``. + This is useful if you want to match an arbitrary literal string that may + have regular expression metacharacters in it. + + .. versionchanged:: 3.3 + The ``'_'`` character is no longer escaped. .. function:: purge() diff --git a/Lib/re.py b/Lib/re.py --- a/Lib/re.py +++ b/Lib/re.py @@ -215,12 +215,14 @@ return _compile(pattern, flags|T) _alphanum_str = frozenset( - "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890") + "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890") _alphanum_bytes = frozenset( - b"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890") + b"_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890") def escape(pattern): - "Escape all non-alphanumeric characters in pattern." + """ + Escape all the characters in pattern except ASCII letters, numbers and '_'. + """ if isinstance(pattern, str): alphanum = _alphanum_str s = list(pattern) diff --git a/Lib/test/test_re.py b/Lib/test/test_re.py --- a/Lib/test/test_re.py +++ b/Lib/test/test_re.py @@ -428,7 +428,7 @@ self.assertEqual(m.span(), span) def test_re_escape(self): - alnum_chars = string.ascii_letters + string.digits + alnum_chars = string.ascii_letters + string.digits + '_' p = ''.join(chr(i) for i in range(256)) for c in p: if c in alnum_chars: @@ -441,7 +441,7 @@ self.assertMatch(re.escape(p), p) def test_re_escape_byte(self): - alnum_chars = (string.ascii_letters + string.digits).encode('ascii') + alnum_chars = (string.ascii_letters + string.digits + '_').encode('ascii') p = bytes(range(256)) for i in p: b = bytes([i]) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -98,6 +98,8 @@ Library ------- +- Issue #2650: re.escape() no longer escapes the '_'. + - Issue #11757: select.select() now raises ValueError when a negative timeout is passed (previously, a select.error with EINVAL would be raised). Patch by Charles-Fran?ois Natali. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Apr 10 14:05:54 2011 From: python-checkins at python.org (nick.coghlan) Date: Sun, 10 Apr 2011 14:05:54 +0200 Subject: [Python-checkins] peps: Updated given statement torture test to show why renaming strategies are flawed Message-ID: http://hg.python.org/peps/rev/fc2aa3ef6d34 changeset: 3863:fc2aa3ef6d34 user: Nick Coghlan date: Sun Apr 10 22:05:30 2011 +1000 summary: Updated given statement torture test to show why renaming strategies are flawed files: pep-3150.txt | 29 ++++++++++++++++++++++++++--- 1 files changed, 26 insertions(+), 3 deletions(-) diff --git a/pep-3150.txt b/pep-3150.txt --- a/pep-3150.txt +++ b/pep-3150.txt @@ -314,16 +314,25 @@ assert d[42] == 42 given: d = b assert "d" not in locals() + y = y given: + x = 42 + def f(): pass + y = locals("x"), f.__name__ + assert "x" not in locals() + assert "f" not in locals() + assert y == (42, "f") Most naive implementations will choke on the first complex assignment, while less naive but still broken implementations will fail when -the torture test is executed at class scope. +the torture test is executed at class scope. Renaming based strategies +struggle to support ``locals()`` correctly and also have problems with +class and function ``__name__`` attributes. And yes, that's a perfectly well-defined assignment statement. Insane, you might rightly say, but legal:: >>> def f(x): return x - ... + ... >>> x = 42 >>> b = {} >>> a = b[f(a)] = x @@ -349,6 +358,10 @@ * Return-based semantics struggle with complex assignment statements like the one in the torture test +The second thought is generally some kind of hidden renaming strategy. This +also creates problems, as Python exposes variables names via the ``locals()`` +dictionary and class and function ``__name__`` attributes. + The most promising approach is one based on symtable analysis and copy-in-copy-out referencing semantics to move any required name bindings between the inner and outer scopes. The torture test above @@ -371,6 +384,16 @@ # Nothing to copy out (not an assignment) _anon2() assert "d" not in locals() + def _anon3() # Nothing to copy in (no references to other variables) + x = 42 + def f(): pass + y = locals("x"), f.__name__ + y = y # Assuming no optimisation of special cases + return y # 'y' reference copied out + y = _anon3() + assert "x" not in locals() + assert "f" not in locals() + assert y == (42, "f") However, as noted in the abstract, an actual implementation of this idea has never been tried. @@ -417,7 +440,7 @@ This document has been placed in the public domain. - + .. Local Variables: mode: indented-text -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Sun Apr 10 21:28:44 2011 From: python-checkins at python.org (r.david.murray) Date: Sun, 10 Apr 2011 21:28:44 +0200 Subject: [Python-checkins] cpython: Use stock assertEqual instead of custom ndiffAssertEqual. Message-ID: http://hg.python.org/cpython/rev/00bfad341323 changeset: 69235:00bfad341323 user: R David Murray date: Sun Apr 10 15:28:29 2011 -0400 summary: Use stock assertEqual instead of custom ndiffAssertEqual. Eventually I'll actually replace the calls in the tests themselves. files: Lib/test/test_email/__init__.py | 10 +--------- 1 files changed, 1 insertions(+), 9 deletions(-) diff --git a/Lib/test/test_email/__init__.py b/Lib/test/test_email/__init__.py --- a/Lib/test/test_email/__init__.py +++ b/Lib/test/test_email/__init__.py @@ -29,15 +29,7 @@ super().__init__(*args, **kw) self.addTypeEqualityFunc(bytes, self.assertBytesEqual) - def ndiffAssertEqual(self, first, second): - """Like assertEqual except use ndiff for readable output.""" - if first != second: - sfirst = str(first) - ssecond = str(second) - rfirst = [repr(line) for line in sfirst.splitlines()] - rsecond = [repr(line) for line in ssecond.splitlines()] - diff = difflib.ndiff(rfirst, rsecond) - raise self.failureException(NL + NL.join(diff)) + ndiffAssertEqual = unittest.TestCase.assertEqual def _msgobj(self, filename): with openfile(filename) as fp: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 11 00:23:29 2011 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 11 Apr 2011 00:23:29 +0200 Subject: [Python-checkins] cpython (3.2): Issue #8428: Fix a race condition in multiprocessing.Pool when terminating Message-ID: http://hg.python.org/cpython/rev/d5e43afeede6 changeset: 69236:d5e43afeede6 branch: 3.2 parent: 69232:87d89f767b23 user: Antoine Pitrou date: Mon Apr 11 00:18:59 2011 +0200 summary: Issue #8428: Fix a race condition in multiprocessing.Pool when terminating worker processes: new processes would be spawned while the pool is being shut down. Patch by Charles-Fran?ois Natali. files: Lib/multiprocessing/pool.py | 9 +++++++-- Misc/NEWS | 4 ++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/Lib/multiprocessing/pool.py b/Lib/multiprocessing/pool.py --- a/Lib/multiprocessing/pool.py +++ b/Lib/multiprocessing/pool.py @@ -322,6 +322,8 @@ while pool._worker_handler._state == RUN and pool._state == RUN: pool._maintain_pool() time.sleep(0.1) + # send sentinel to stop workers + pool._taskqueue.put(None) debug('worker handler exiting') @staticmethod @@ -440,7 +442,6 @@ if self._state == RUN: self._state = CLOSE self._worker_handler._state = CLOSE - self._taskqueue.put(None) def terminate(self): debug('terminating pool') @@ -474,7 +475,6 @@ worker_handler._state = TERMINATE task_handler._state = TERMINATE - taskqueue.put(None) # sentinel debug('helping task handler/workers to finish') cls._help_stuff_finish(inqueue, task_handler, len(pool)) @@ -484,6 +484,11 @@ result_handler._state = TERMINATE outqueue.put(None) # sentinel + # We must wait for the worker handler to exit before terminating + # workers because we don't want workers to be restarted behind our back. + debug('joining worker handler') + worker_handler.join() + # Terminate workers which haven't already finished. if pool and hasattr(pool[0], 'terminate'): debug('terminating workers') diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -53,6 +53,10 @@ Library ------- +- Issue #8428: Fix a race condition in multiprocessing.Pool when terminating + worker processes: new processes would be spawned while the pool is being + shut down. Patch by Charles-Fran?ois Natali. + - Issue #7311: fix html.parser to accept non-ASCII attribute values. - Issue #11605: email.parser.BytesFeedParser was incorrectly converting multipart -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 11 00:23:31 2011 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 11 Apr 2011 00:23:31 +0200 Subject: [Python-checkins] cpython (3.2): Issue #11814: Fix likely typo in multiprocessing.Pool._terminate(). Message-ID: http://hg.python.org/cpython/rev/c046b7e1087b changeset: 69237:c046b7e1087b branch: 3.2 user: Antoine Pitrou date: Mon Apr 11 00:20:23 2011 +0200 summary: Issue #11814: Fix likely typo in multiprocessing.Pool._terminate(). files: Lib/multiprocessing/pool.py | 2 +- Misc/NEWS | 2 ++ 2 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Lib/multiprocessing/pool.py b/Lib/multiprocessing/pool.py --- a/Lib/multiprocessing/pool.py +++ b/Lib/multiprocessing/pool.py @@ -500,7 +500,7 @@ task_handler.join() debug('joining result handler') - task_handler.join() + result_handler.join() if pool and hasattr(pool[0], 'terminate'): debug('joining pool workers') diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -53,6 +53,8 @@ Library ------- +- Issue #11814: Fix likely typo in multiprocessing.Pool._terminate(). + - Issue #8428: Fix a race condition in multiprocessing.Pool when terminating worker processes: new processes would be spawned while the pool is being shut down. Patch by Charles-Fran?ois Natali. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 11 00:23:38 2011 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 11 Apr 2011 00:23:38 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge from 3.2 (issue #11814, issue #8428) Message-ID: http://hg.python.org/cpython/rev/76a3fc180ce0 changeset: 69238:76a3fc180ce0 parent: 69235:00bfad341323 parent: 69237:c046b7e1087b user: Antoine Pitrou date: Mon Apr 11 00:22:08 2011 +0200 summary: Merge from 3.2 (issue #11814, issue #8428) files: Lib/multiprocessing/pool.py | 11 ++++++++--- Misc/NEWS | 6 ++++++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/Lib/multiprocessing/pool.py b/Lib/multiprocessing/pool.py --- a/Lib/multiprocessing/pool.py +++ b/Lib/multiprocessing/pool.py @@ -322,6 +322,8 @@ while pool._worker_handler._state == RUN and pool._state == RUN: pool._maintain_pool() time.sleep(0.1) + # send sentinel to stop workers + pool._taskqueue.put(None) debug('worker handler exiting') @staticmethod @@ -440,7 +442,6 @@ if self._state == RUN: self._state = CLOSE self._worker_handler._state = CLOSE - self._taskqueue.put(None) def terminate(self): debug('terminating pool') @@ -474,7 +475,6 @@ worker_handler._state = TERMINATE task_handler._state = TERMINATE - taskqueue.put(None) # sentinel debug('helping task handler/workers to finish') cls._help_stuff_finish(inqueue, task_handler, len(pool)) @@ -484,6 +484,11 @@ result_handler._state = TERMINATE outqueue.put(None) # sentinel + # We must wait for the worker handler to exit before terminating + # workers because we don't want workers to be restarted behind our back. + debug('joining worker handler') + worker_handler.join() + # Terminate workers which haven't already finished. if pool and hasattr(pool[0], 'terminate'): debug('terminating workers') @@ -495,7 +500,7 @@ task_handler.join() debug('joining result handler') - task_handler.join() + result_handler.join() if pool and hasattr(pool[0], 'terminate'): debug('joining pool workers') diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -98,6 +98,12 @@ Library ------- +- Issue #11814: Fix likely typo in multiprocessing.Pool._terminate(). + +- Issue #8428: Fix a race condition in multiprocessing.Pool when terminating + worker processes: new processes would be spawned while the pool is being + shut down. Patch by Charles-Fran?ois Natali. + - Issue #2650: re.escape() no longer escapes the '_'. - Issue #11757: select.select() now raises ValueError when a negative timeout -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 11 00:28:24 2011 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 11 Apr 2011 00:28:24 +0200 Subject: [Python-checkins] cpython (2.7): Issue #8428: Fix a race condition in multiprocessing.Pool when terminating Message-ID: http://hg.python.org/cpython/rev/dfc61dc14f59 changeset: 69239:dfc61dc14f59 branch: 2.7 parent: 69228:3630bc3d5a88 user: Antoine Pitrou date: Mon Apr 11 00:26:42 2011 +0200 summary: Issue #8428: Fix a race condition in multiprocessing.Pool when terminating worker processes: new processes would be spawned while the pool is being shut down. Patch by Charles-Fran?ois Natali. files: Lib/multiprocessing/pool.py | 9 +++++++-- Misc/NEWS | 4 ++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/Lib/multiprocessing/pool.py b/Lib/multiprocessing/pool.py --- a/Lib/multiprocessing/pool.py +++ b/Lib/multiprocessing/pool.py @@ -295,6 +295,8 @@ while pool._worker_handler._state == RUN and pool._state == RUN: pool._maintain_pool() time.sleep(0.1) + # send sentinel to stop workers + pool._taskqueue.put(None) debug('worker handler exiting') @staticmethod @@ -413,7 +415,6 @@ if self._state == RUN: self._state = CLOSE self._worker_handler._state = CLOSE - self._taskqueue.put(None) def terminate(self): debug('terminating pool') @@ -447,7 +448,6 @@ worker_handler._state = TERMINATE task_handler._state = TERMINATE - taskqueue.put(None) # sentinel debug('helping task handler/workers to finish') cls._help_stuff_finish(inqueue, task_handler, len(pool)) @@ -457,6 +457,11 @@ result_handler._state = TERMINATE outqueue.put(None) # sentinel + # We must wait for the worker handler to exit before terminating + # workers because we don't want workers to be restarted behind our back. + debug('joining worker handler') + worker_handler.join() + # Terminate workers which haven't already finished. if pool and hasattr(pool[0], 'terminate'): debug('terminating workers') diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -51,6 +51,10 @@ Library ------- +- Issue #8428: Fix a race condition in multiprocessing.Pool when terminating + worker processes: new processes would be spawned while the pool is being + shut down. Patch by Charles-Fran?ois Natali. + - Issue #7311: fix HTMLParser to accept non-ASCII attribute values. - Issue #10963: Ensure that subprocess.communicate() never raises EPIPE. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 11 02:24:41 2011 From: python-checkins at python.org (raymond.hettinger) Date: Mon, 11 Apr 2011 02:24:41 +0200 Subject: [Python-checkins] cpython (3.2): Cleanup and modernize code prior to working on Issue 11747. Message-ID: http://hg.python.org/cpython/rev/36648097fcd4 changeset: 69240:36648097fcd4 branch: 3.2 parent: 69237:c046b7e1087b user: Raymond Hettinger date: Sun Apr 10 17:14:56 2011 -0700 summary: Cleanup and modernize code prior to working on Issue 11747. files: Lib/difflib.py | 53 +++++++++++++++++++------------------ 1 files changed, 27 insertions(+), 26 deletions(-) diff --git a/Lib/difflib.py b/Lib/difflib.py --- a/Lib/difflib.py +++ b/Lib/difflib.py @@ -1188,22 +1188,23 @@ started = False for group in SequenceMatcher(None,a,b).get_grouped_opcodes(n): if not started: - fromdate = '\t%s' % fromfiledate if fromfiledate else '' - todate = '\t%s' % tofiledate if tofiledate else '' - yield '--- %s%s%s' % (fromfile, fromdate, lineterm) - yield '+++ %s%s%s' % (tofile, todate, lineterm) started = True - i1, i2, j1, j2 = group[0][1], group[-1][2], group[0][3], group[-1][4] - yield "@@ -%d,%d +%d,%d @@%s" % (i1+1, i2-i1, j1+1, j2-j1, lineterm) + fromdate = '\t{}'.format(fromfiledate) if fromfiledate else '' + todate = '\t{}'.format(tofiledate) if tofiledate else '' + yield '--- {}{}{}'.format(fromfile, fromdate, lineterm) + yield '+++ {}{}{}'.format(tofile, todate, lineterm) + first, last = group[0], group[-1] + i1, i2, j1, j2 = first[1], last[2], first[3], last[4] + yield '@@ -{},{} +{},{} @@{}'.format(i1+1, i2-i1, j1+1, j2-j1, lineterm) for tag, i1, i2, j1, j2 in group: if tag == 'equal': for line in a[i1:i2]: yield ' ' + line continue - if tag == 'replace' or tag == 'delete': + if tag in {'replace', 'delete'}: for line in a[i1:i2]: yield '-' + line - if tag == 'replace' or tag == 'insert': + if tag in {'replace', 'insert'}: for line in b[j1:j2]: yield '+' + line @@ -1252,38 +1253,38 @@ four """ + prefix = dict(insert='+ ', delete='- ', replace='! ', equal=' ') started = False - prefixmap = {'insert':'+ ', 'delete':'- ', 'replace':'! ', 'equal':' '} for group in SequenceMatcher(None,a,b).get_grouped_opcodes(n): if not started: - fromdate = '\t%s' % fromfiledate if fromfiledate else '' - todate = '\t%s' % tofiledate if tofiledate else '' - yield '*** %s%s%s' % (fromfile, fromdate, lineterm) - yield '--- %s%s%s' % (tofile, todate, lineterm) started = True + fromdate = '\t{}'.format(fromfiledate) if fromfiledate else '' + todate = '\t{}'.format(tofiledate) if tofiledate else '' + yield '*** {}{}{}'.format(fromfile, fromdate, lineterm) + yield '--- {}{}{}'.format(tofile, todate, lineterm) - yield '***************%s' % (lineterm,) - if group[-1][2] - group[0][1] >= 2: - yield '*** %d,%d ****%s' % (group[0][1]+1, group[-1][2], lineterm) + first, last = group[0], group[-1] + yield '***************{}'.format(lineterm) + + if last[2] - first[1] > 1: + yield '*** {},{} ****{}'.format(first[1]+1, last[2], lineterm) else: - yield '*** %d ****%s' % (group[-1][2], lineterm) - visiblechanges = [e for e in group if e[0] in ('replace', 'delete')] - if visiblechanges: + yield '*** {} ****{}'.format(last[2], lineterm) + if any(tag in {'replace', 'delete'} for tag, _, _, _, _ in group): for tag, i1, i2, _, _ in group: if tag != 'insert': for line in a[i1:i2]: - yield prefixmap[tag] + line + yield prefix[tag] + line - if group[-1][4] - group[0][3] >= 2: - yield '--- %d,%d ----%s' % (group[0][3]+1, group[-1][4], lineterm) + if last[4] - first[3] > 1: + yield '--- {},{} ----{}'.format(first[3]+1, last[4], lineterm) else: - yield '--- %d ----%s' % (group[-1][4], lineterm) - visiblechanges = [e for e in group if e[0] in ('replace', 'insert')] - if visiblechanges: + yield '--- {} ----{}'.format(last[4], lineterm) + if any(tag in {'replace', 'insert'} for tag, _, _, _, _ in group): for tag, _, _, j1, j2 in group: if tag != 'delete': for line in b[j1:j2]: - yield prefixmap[tag] + line + yield prefix[tag] + line def ndiff(a, b, linejunk=None, charjunk=IS_CHARACTER_JUNK): r""" -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 11 02:24:43 2011 From: python-checkins at python.org (raymond.hettinger) Date: Mon, 11 Apr 2011 02:24:43 +0200 Subject: [Python-checkins] cpython: Cleanup and modernize code prior to working on Issue 11747. Message-ID: http://hg.python.org/cpython/rev/58a3bfcc70f7 changeset: 69241:58a3bfcc70f7 parent: 69238:76a3fc180ce0 user: Raymond Hettinger date: Sun Apr 10 17:23:32 2011 -0700 summary: Cleanup and modernize code prior to working on Issue 11747. files: Lib/difflib.py | 53 +++++++++++++++++++------------------ 1 files changed, 27 insertions(+), 26 deletions(-) diff --git a/Lib/difflib.py b/Lib/difflib.py --- a/Lib/difflib.py +++ b/Lib/difflib.py @@ -1188,22 +1188,23 @@ started = False for group in SequenceMatcher(None,a,b).get_grouped_opcodes(n): if not started: - fromdate = '\t%s' % fromfiledate if fromfiledate else '' - todate = '\t%s' % tofiledate if tofiledate else '' - yield '--- %s%s%s' % (fromfile, fromdate, lineterm) - yield '+++ %s%s%s' % (tofile, todate, lineterm) started = True - i1, i2, j1, j2 = group[0][1], group[-1][2], group[0][3], group[-1][4] - yield "@@ -%d,%d +%d,%d @@%s" % (i1+1, i2-i1, j1+1, j2-j1, lineterm) + fromdate = '\t{}'.format(fromfiledate) if fromfiledate else '' + todate = '\t{}'.format(tofiledate) if tofiledate else '' + yield '--- {}{}{}'.format(fromfile, fromdate, lineterm) + yield '+++ {}{}{}'.format(tofile, todate, lineterm) + first, last = group[0], group[-1] + i1, i2, j1, j2 = first[1], last[2], first[3], last[4] + yield '@@ -{},{} +{},{} @@{}'.format(i1+1, i2-i1, j1+1, j2-j1, lineterm) for tag, i1, i2, j1, j2 in group: if tag == 'equal': for line in a[i1:i2]: yield ' ' + line continue - if tag == 'replace' or tag == 'delete': + if tag in {'replace', 'delete'}: for line in a[i1:i2]: yield '-' + line - if tag == 'replace' or tag == 'insert': + if tag in {'replace', 'insert'}: for line in b[j1:j2]: yield '+' + line @@ -1252,38 +1253,38 @@ four """ + prefix = dict(insert='+ ', delete='- ', replace='! ', equal=' ') started = False - prefixmap = {'insert':'+ ', 'delete':'- ', 'replace':'! ', 'equal':' '} for group in SequenceMatcher(None,a,b).get_grouped_opcodes(n): if not started: - fromdate = '\t%s' % fromfiledate if fromfiledate else '' - todate = '\t%s' % tofiledate if tofiledate else '' - yield '*** %s%s%s' % (fromfile, fromdate, lineterm) - yield '--- %s%s%s' % (tofile, todate, lineterm) started = True + fromdate = '\t{}'.format(fromfiledate) if fromfiledate else '' + todate = '\t{}'.format(tofiledate) if tofiledate else '' + yield '*** {}{}{}'.format(fromfile, fromdate, lineterm) + yield '--- {}{}{}'.format(tofile, todate, lineterm) - yield '***************%s' % (lineterm,) - if group[-1][2] - group[0][1] >= 2: - yield '*** %d,%d ****%s' % (group[0][1]+1, group[-1][2], lineterm) + first, last = group[0], group[-1] + yield '***************{}'.format(lineterm) + + if last[2] - first[1] > 1: + yield '*** {},{} ****{}'.format(first[1]+1, last[2], lineterm) else: - yield '*** %d ****%s' % (group[-1][2], lineterm) - visiblechanges = [e for e in group if e[0] in {'replace', 'delete'}] - if visiblechanges: + yield '*** {} ****{}'.format(last[2], lineterm) + if any(tag in {'replace', 'delete'} for tag, _, _, _, _ in group): for tag, i1, i2, _, _ in group: if tag != 'insert': for line in a[i1:i2]: - yield prefixmap[tag] + line + yield prefix[tag] + line - if group[-1][4] - group[0][3] >= 2: - yield '--- %d,%d ----%s' % (group[0][3]+1, group[-1][4], lineterm) + if last[4] - first[3] > 1: + yield '--- {},{} ----{}'.format(first[3]+1, last[4], lineterm) else: - yield '--- %d ----%s' % (group[-1][4], lineterm) - visiblechanges = [e for e in group if e[0] in {'replace', 'insert'}] - if visiblechanges: + yield '--- {} ----{}'.format(last[4], lineterm) + if any(tag in {'replace', 'insert'} for tag, _, _, _, _ in group): for tag, _, _, j1, j2 in group: if tag != 'delete': for line in b[j1:j2]: - yield prefixmap[tag] + line + yield prefix[tag] + line def ndiff(a, b, linejunk=None, charjunk=IS_CHARACTER_JUNK): r""" -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 11 02:24:48 2011 From: python-checkins at python.org (raymond.hettinger) Date: Mon, 11 Apr 2011 02:24:48 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge Message-ID: http://hg.python.org/cpython/rev/3644a1e3a289 changeset: 69242:3644a1e3a289 parent: 69241:58a3bfcc70f7 parent: 69240:36648097fcd4 user: Raymond Hettinger date: Sun Apr 10 17:24:14 2011 -0700 summary: Merge files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 11 02:45:55 2011 From: python-checkins at python.org (ezio.melotti) Date: Mon, 11 Apr 2011 02:45:55 +0200 Subject: [Python-checkins] cpython (2.7): #4877: Fix a segfault in xml.parsers.expat while attempting to parse a closed Message-ID: http://hg.python.org/cpython/rev/28705a7987c5 changeset: 69243:28705a7987c5 branch: 2.7 parent: 69239:dfc61dc14f59 user: Ezio Melotti date: Mon Apr 11 03:44:28 2011 +0300 summary: #4877: Fix a segfault in xml.parsers.expat while attempting to parse a closed file. files: Lib/test/test_pyexpat.py | 11 ++++++++ Misc/NEWS | 5 ++- Modules/pyexpat.c | 38 ++++++++------------------- 3 files changed, 27 insertions(+), 27 deletions(-) diff --git a/Lib/test/test_pyexpat.py b/Lib/test/test_pyexpat.py --- a/Lib/test/test_pyexpat.py +++ b/Lib/test/test_pyexpat.py @@ -6,6 +6,7 @@ from xml.parsers import expat +from test import test_support from test.test_support import sortdict, run_unittest @@ -217,6 +218,16 @@ self.assertEqual(op[15], "External entity ref: (None, u'entity.file', None)") self.assertEqual(op[16], "End element: u'root'") + # Issue 4877: expat.ParseFile causes segfault on a closed file. + fp = open(test_support.TESTFN, 'wb') + try: + fp.close() + parser = expat.ParserCreate() + with self.assertRaises(ValueError): + parser.ParseFile(fp) + finally: + test_support.unlink(test_support.TESTFN) + class NamespaceSeparatorTest(unittest.TestCase): def test_legal(self): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -51,11 +51,14 @@ Library ------- +- Issue #4877: Fix a segfault in xml.parsers.expat while attempting to parse + a closed file. + - Issue #8428: Fix a race condition in multiprocessing.Pool when terminating worker processes: new processes would be spawned while the pool is being shut down. Patch by Charles-Fran?ois Natali. -- Issue #7311: fix HTMLParser to accept non-ASCII attribute values. +- Issue #7311: Fix HTMLParser to accept non-ASCII attribute values. - Issue #10963: Ensure that subprocess.communicate() never raises EPIPE. diff --git a/Modules/pyexpat.c b/Modules/pyexpat.c --- a/Modules/pyexpat.c +++ b/Modules/pyexpat.c @@ -962,21 +962,15 @@ xmlparse_ParseFile(xmlparseobject *self, PyObject *f) { int rv = 1; - FILE *fp; PyObject *readmethod = NULL; - if (PyFile_Check(f)) { - fp = PyFile_AsFile(f); - } - else { - fp = NULL; - readmethod = PyObject_GetAttrString(f, "read"); - if (readmethod == NULL) { - PyErr_Clear(); - PyErr_SetString(PyExc_TypeError, - "argument must have 'read' attribute"); - return NULL; - } + readmethod = PyObject_GetAttrString(f, "read"); + if (readmethod == NULL) { + PyErr_Clear(); + PyErr_SetString(PyExc_TypeError, + "argument must have 'read' attribute"); + return NULL; + } for (;;) { int bytes_read; @@ -986,20 +980,12 @@ return PyErr_NoMemory(); } - if (fp) { - bytes_read = fread(buf, sizeof(char), BUF_SIZE, fp); - if (bytes_read < 0) { - PyErr_SetFromErrno(PyExc_IOError); - return NULL; - } + bytes_read = readinst(buf, BUF_SIZE, readmethod); + if (bytes_read < 0) { + Py_XDECREF(readmethod); + return NULL; } - else { - bytes_read = readinst(buf, BUF_SIZE, readmethod); - if (bytes_read < 0) { - Py_XDECREF(readmethod); - return NULL; - } - } + rv = XML_ParseBuffer(self->itself, bytes_read, bytes_read == 0); if (PyErr_Occurred()) { Py_XDECREF(readmethod); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 11 02:45:56 2011 From: python-checkins at python.org (ezio.melotti) Date: Mon, 11 Apr 2011 02:45:56 +0200 Subject: [Python-checkins] cpython (2.7): Remove unnecessary call to PyErr_Clear. Message-ID: http://hg.python.org/cpython/rev/ba699cf9bdbb changeset: 69244:ba699cf9bdbb branch: 2.7 user: Ezio Melotti date: Mon Apr 11 03:45:25 2011 +0300 summary: Remove unnecessary call to PyErr_Clear. files: Modules/pyexpat.c | 1 - 1 files changed, 0 insertions(+), 1 deletions(-) diff --git a/Modules/pyexpat.c b/Modules/pyexpat.c --- a/Modules/pyexpat.c +++ b/Modules/pyexpat.c @@ -966,7 +966,6 @@ readmethod = PyObject_GetAttrString(f, "read"); if (readmethod == NULL) { - PyErr_Clear(); PyErr_SetString(PyExc_TypeError, "argument must have 'read' attribute"); return NULL; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 11 02:51:35 2011 From: python-checkins at python.org (ezio.melotti) Date: Mon, 11 Apr 2011 02:51:35 +0200 Subject: [Python-checkins] cpython (3.2): Remove unnecessary call to PyErr_Clear. Message-ID: http://hg.python.org/cpython/rev/6b4467e71872 changeset: 69245:6b4467e71872 branch: 3.2 parent: 69240:36648097fcd4 user: Ezio Melotti date: Mon Apr 11 03:48:57 2011 +0300 summary: Remove unnecessary call to PyErr_Clear. files: Modules/pyexpat.c | 1 - 1 files changed, 0 insertions(+), 1 deletions(-) diff --git a/Modules/pyexpat.c b/Modules/pyexpat.c --- a/Modules/pyexpat.c +++ b/Modules/pyexpat.c @@ -846,7 +846,6 @@ readmethod = PyObject_GetAttrString(f, "read"); if (readmethod == NULL) { - PyErr_Clear(); PyErr_SetString(PyExc_TypeError, "argument must have 'read' attribute"); return NULL; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 11 02:51:36 2011 From: python-checkins at python.org (ezio.melotti) Date: Mon, 11 Apr 2011 02:51:36 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge with 3.2. Message-ID: http://hg.python.org/cpython/rev/2d1d9759d3a4 changeset: 69246:2d1d9759d3a4 parent: 69242:3644a1e3a289 parent: 69245:6b4467e71872 user: Ezio Melotti date: Mon Apr 11 03:51:14 2011 +0300 summary: Merge with 3.2. files: Modules/pyexpat.c | 1 - 1 files changed, 0 insertions(+), 1 deletions(-) diff --git a/Modules/pyexpat.c b/Modules/pyexpat.c --- a/Modules/pyexpat.c +++ b/Modules/pyexpat.c @@ -847,7 +847,6 @@ readmethod = PyObject_GetAttrString(f, "read"); if (readmethod == NULL) { - PyErr_Clear(); PyErr_SetString(PyExc_TypeError, "argument must have 'read' attribute"); return NULL; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 11 04:25:36 2011 From: python-checkins at python.org (reid.kleckner) Date: Mon, 11 Apr 2011 04:25:36 +0200 Subject: [Python-checkins] cpython: Add Misc/NEWS "What's New" entry for subprocess timeouts. Message-ID: http://hg.python.org/cpython/rev/9140f2363623 changeset: 69247:9140f2363623 user: Reid Kleckner date: Sun Apr 10 22:23:08 2011 -0400 summary: Add Misc/NEWS "What's New" entry for subprocess timeouts. files: Misc/NEWS | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,11 @@ Core and Builtins ----------------- +- Issue #5673: Added a `timeout` keyword argument to subprocess.Popen.wait, + subprocess.Popen.communicated, subprocess.call, subprocess.check_call, and + subprocess.check_output. If the blocking operation takes more than `timeout` + seconds, the `subprocess.TimeoutExpired` exception is raised. + - Issue #11650: PyOS_StdioReadline() retries fgets() if it was interrupted (EINTR), for example if the program is stopped with CTRL+z on Mac OS X. Patch written by Charles-Francois Natali. -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Mon Apr 11 05:01:13 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Mon, 11 Apr 2011 05:01:13 +0200 Subject: [Python-checkins] Daily reference leaks (2d1d9759d3a4): sum=0 Message-ID: results for 2d1d9759d3a4 on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogl1EJSG', '-x'] From python-checkins at python.org Mon Apr 11 09:44:03 2011 From: python-checkins at python.org (vinay.sajip) Date: Mon, 11 Apr 2011 09:44:03 +0200 Subject: [Python-checkins] cpython: Added 'handlers' argument to logging.basicConfig. Message-ID: http://hg.python.org/cpython/rev/fbf5e4b1e52a changeset: 69248:fbf5e4b1e52a user: Vinay Sajip date: Mon Apr 11 08:42:07 2011 +0100 summary: Added 'handlers' argument to logging.basicConfig. files: Doc/library/logging.rst | 17 ++++++++++- Lib/logging/__init__.py | 42 ++++++++++++++++++++++------ Lib/test/test_logging.py | 20 +++++++++++++ Misc/NEWS | 4 ++ 4 files changed, 73 insertions(+), 10 deletions(-) diff --git a/Doc/library/logging.rst b/Doc/library/logging.rst --- a/Doc/library/logging.rst +++ b/Doc/library/logging.rst @@ -983,12 +983,27 @@ | ``stream`` | Use the specified stream to initialize the | | | StreamHandler. Note that this argument is | | | incompatible with 'filename' - if both are | - | | present, 'stream' is ignored. | + | | present, a ``ValueError`` is raised. | + +--------------+---------------------------------------------+ + | ``handlers`` | If specified, this should be an iterable of | + | | already created handlers to add to the root | + | | logger. Any handlers which don't already | + | | have a formatter set will be assigned the | + | | default formatter created in this function. | + | | Note that this argument is incompatible | + | | with 'filename' or 'stream' - if both are | + | | present, a ``ValueError`` is raised. | +--------------+---------------------------------------------+ .. versionchanged:: 3.2 The ``style`` argument was added. + .. versionchanged:: 3.3 + The ``handlers`` argument was added. Additional checks were added to + catch situations where incompatible arguments are specified (e.g. + ``handlers`` together with ``stream`` or ``filename``, or ``stream`` + together with ``filename``). + .. function:: shutdown() diff --git a/Lib/logging/__init__.py b/Lib/logging/__init__.py --- a/Lib/logging/__init__.py +++ b/Lib/logging/__init__.py @@ -1650,6 +1650,10 @@ stream Use the specified stream to initialize the StreamHandler. Note that this argument is incompatible with 'filename' - if both are present, 'stream' is ignored. + handlers If specified, this should be an iterable of already created + handlers, which will be added to the root handler. Any handler + in the list which does not have a formatter assigned will be + assigned the formatter created in this function. Note that you could specify a stream created using open(filename, mode) rather than passing the filename and mode in. However, it should be @@ -1657,27 +1661,47 @@ using sys.stdout or sys.stderr), whereas FileHandler closes its stream when the handler is closed. - .. versionchanged: 3.2 + .. versionchanged:: 3.2 Added the ``style`` parameter. + + .. versionchanged:: 3.3 + Added the ``handlers`` parameter. A ``ValueError`` is now thrown for + incompatible arguments (e.g. ``handlers`` specified together with + ``filename``/``filemode``, or ``filename``/``filemode`` specified + together with ``stream``, or ``handlers`` specified together with + ``stream``. """ # Add thread safety in case someone mistakenly calls # basicConfig() from multiple threads _acquireLock() try: if len(root.handlers) == 0: - filename = kwargs.get("filename") - if filename: - mode = kwargs.get("filemode", 'a') - hdlr = FileHandler(filename, mode) + handlers = kwargs.get("handlers") + if handlers is None: + if "stream" in kwargs and "filename" in kwargs: + raise ValueError("'stream' and 'filename' should not be " + "specified together") else: - stream = kwargs.get("stream") - hdlr = StreamHandler(stream) + if "stream" in kwargs or "filename" in kwargs: + raise ValueError("'stream' or 'filename' should not be " + "specified together with 'handlers'") + if handlers is None: + filename = kwargs.get("filename") + if filename: + mode = kwargs.get("filemode", 'a') + h = FileHandler(filename, mode) + else: + stream = kwargs.get("stream") + h = StreamHandler(stream) + handlers = [h] fs = kwargs.get("format", BASIC_FORMAT) dfs = kwargs.get("datefmt", None) style = kwargs.get("style", '%') fmt = Formatter(fs, dfs, style) - hdlr.setFormatter(fmt) - root.addHandler(hdlr) + for h in handlers: + if h.formatter is None: + h.setFormatter(fmt) + root.addHandler(h) level = kwargs.get("level") if level is not None: root.setLevel(level) 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 @@ -2482,6 +2482,26 @@ logging.basicConfig(level=57) self.assertEqual(logging.root.level, 57) + def test_incompatible(self): + assertRaises = self.assertRaises + handlers = [logging.StreamHandler()] + stream = sys.stderr + assertRaises(ValueError, logging.basicConfig, filename='test.log', + stream=stream) + assertRaises(ValueError, logging.basicConfig, filename='test.log', + handlers=handlers) + assertRaises(ValueError, logging.basicConfig, stream=stream, + handlers=handlers) + + def test_handlers(self): + handlers = [logging.StreamHandler(), logging.StreamHandler(sys.stdout)] + logging.basicConfig(handlers=handlers) + self.assertIs(handlers[0], logging.root.handlers[0]) + self.assertIs(handlers[1], logging.root.handlers[1]) + self.assertIsNotNone(handlers[0].formatter) + self.assertIsNotNone(handlers[1].formatter) + self.assertIs(handlers[0].formatter, handlers[1].formatter) + def _test_log(self, method, level=None): # logging.root has no handlers so basicConfig should be called called = [] diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -103,6 +103,10 @@ Library ------- +- logging.basicConfig now supports an optional 'handlers' argument taking an + iterable of handlers to be added to the root logger. Additional parameter + checks were also added to basicConfig. + - Issue #11814: Fix likely typo in multiprocessing.Pool._terminate(). - Issue #8428: Fix a race condition in multiprocessing.Pool when terminating -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 11 09:44:03 2011 From: python-checkins at python.org (vinay.sajip) Date: Mon, 11 Apr 2011 09:44:03 +0200 Subject: [Python-checkins] cpython: Whitespace normalized. Message-ID: http://hg.python.org/cpython/rev/c9e9142d82d6 changeset: 69249:c9e9142d82d6 user: Vinay Sajip date: Mon Apr 11 08:43:52 2011 +0100 summary: Whitespace normalized. files: Lib/logging/__init__.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/logging/__init__.py b/Lib/logging/__init__.py --- a/Lib/logging/__init__.py +++ b/Lib/logging/__init__.py @@ -1663,7 +1663,7 @@ .. versionchanged:: 3.2 Added the ``style`` parameter. - + .. versionchanged:: 3.3 Added the ``handlers`` parameter. A ``ValueError`` is now thrown for incompatible arguments (e.g. ``handlers`` specified together with -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 11 22:11:11 2011 From: python-checkins at python.org (raymond.hettinger) Date: Mon, 11 Apr 2011 22:11:11 +0200 Subject: [Python-checkins] cpython (3.2): Issue #11747: Fix range formatting in context and unified diffs. Message-ID: http://hg.python.org/cpython/rev/a2ee967de44f changeset: 69250:a2ee967de44f branch: 3.2 parent: 69245:6b4467e71872 user: Raymond Hettinger date: Mon Apr 11 12:40:58 2011 -0700 summary: Issue #11747: Fix range formatting in context and unified diffs. files: Lib/difflib.py | 34 ++++++++++++++++++--------- Lib/test/test_difflib.py | 16 +++++++++++++ Misc/NEWS | 3 ++ 3 files changed, 42 insertions(+), 11 deletions(-) diff --git a/Lib/difflib.py b/Lib/difflib.py --- a/Lib/difflib.py +++ b/Lib/difflib.py @@ -1144,6 +1144,17 @@ return ch in ws +def _format_range(start, stop): + 'Convert range to the "ed" format' + # Per the diff spec at http://www.unix.org/single_unix_specification/ + beginning = start + 1 # lines start numbering with one + length = stop - start + if length == 1: + return '{}'.format(beginning) + if not length: + beginning -= 1 # empty ranges begin at line just before the range + return '{},{}'.format(beginning, length) + def unified_diff(a, b, fromfile='', tofile='', fromfiledate='', tofiledate='', n=3, lineterm='\n'): r""" @@ -1193,9 +1204,12 @@ todate = '\t{}'.format(tofiledate) if tofiledate else '' yield '--- {}{}{}'.format(fromfile, fromdate, lineterm) yield '+++ {}{}{}'.format(tofile, todate, lineterm) + first, last = group[0], group[-1] - i1, i2, j1, j2 = first[1], last[2], first[3], last[4] - yield '@@ -{},{} +{},{} @@{}'.format(i1+1, i2-i1, j1+1, j2-j1, lineterm) + file1_range = _format_range(first[1], last[2]) + file2_range = _format_range(first[3], last[4]) + yield '@@ -{} +{} @@{}'.format(file1_range, file2_range, lineterm) + for tag, i1, i2, j1, j2 in group: if tag == 'equal': for line in a[i1:i2]: @@ -1264,22 +1278,20 @@ yield '--- {}{}{}'.format(tofile, todate, lineterm) first, last = group[0], group[-1] - yield '***************{}'.format(lineterm) + yield '***************' + lineterm - if last[2] - first[1] > 1: - yield '*** {},{} ****{}'.format(first[1]+1, last[2], lineterm) - else: - yield '*** {} ****{}'.format(last[2], lineterm) + file1_range = _format_range(first[1], last[2]) + yield '*** {} ****{}'.format(file1_range, lineterm) + if any(tag in {'replace', 'delete'} for tag, _, _, _, _ in group): for tag, i1, i2, _, _ in group: if tag != 'insert': for line in a[i1:i2]: yield prefix[tag] + line - if last[4] - first[3] > 1: - yield '--- {},{} ----{}'.format(first[3]+1, last[4], lineterm) - else: - yield '--- {} ----{}'.format(last[4], lineterm) + file2_range = _format_range(first[3], last[4]) + yield '--- {} ----{}'.format(file2_range, lineterm) + if any(tag in {'replace', 'insert'} for tag, _, _, _, _ in group): for tag, _, _, j1, j2 in group: if tag != 'delete': diff --git a/Lib/test/test_difflib.py b/Lib/test/test_difflib.py --- a/Lib/test/test_difflib.py +++ b/Lib/test/test_difflib.py @@ -236,6 +236,22 @@ cd = difflib.context_diff(*args, lineterm='') self.assertEqual(list(cd)[0:2], ["*** Original", "--- Current"]) + def test_range_format(self): + # Per the diff spec at http://www.unix.org/single_unix_specification/ + spec = '''\ + Each field shall be of the form: + %1d", if the range contains exactly one line, + and: + "%1d,%1d", , otherwise. + If a range is empty, its beginning line number shall be the number of + the line just before the range, or 0 if the empty range starts the file. + ''' + fmt = difflib._format_range + self.assertEqual(fmt(3,3), '3,0') + self.assertEqual(fmt(3,4), '4') + self.assertEqual(fmt(3,5), '4,2') + self.assertEqual(fmt(3,6), '4,3') + self.assertEqual(fmt(0,0), '0,0') def test_main(): difflib.HtmlDiff._default_prefix = 0 diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -55,6 +55,9 @@ - Issue #11814: Fix likely typo in multiprocessing.Pool._terminate(). +- Issue #11747: Fix range formatting in difflib.context_diff() and + difflib.unified_diff(). + - Issue #8428: Fix a race condition in multiprocessing.Pool when terminating worker processes: new processes would be spawned while the pool is being shut down. Patch by Charles-Fran?ois Natali. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 11 22:11:12 2011 From: python-checkins at python.org (raymond.hettinger) Date: Mon, 11 Apr 2011 22:11:12 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Issue #11747: Fix range formatting in context and unified diffs. Message-ID: http://hg.python.org/cpython/rev/1e5e3bb3e1f1 changeset: 69251:1e5e3bb3e1f1 parent: 69249:c9e9142d82d6 parent: 69250:a2ee967de44f user: Raymond Hettinger date: Mon Apr 11 12:42:59 2011 -0700 summary: Issue #11747: Fix range formatting in context and unified diffs. files: Lib/difflib.py | 34 ++++++++++++++++++--------- Lib/test/test_difflib.py | 16 +++++++++++++ Misc/NEWS | 3 ++ 3 files changed, 42 insertions(+), 11 deletions(-) diff --git a/Lib/difflib.py b/Lib/difflib.py --- a/Lib/difflib.py +++ b/Lib/difflib.py @@ -1144,6 +1144,17 @@ return ch in ws +def _format_range(start, stop): + 'Convert range to the "ed" format' + # Per the diff spec at http://www.unix.org/single_unix_specification/ + beginning = start + 1 # lines start numbering with one + length = stop - start + if length == 1: + return '{}'.format(beginning) + if not length: + beginning -= 1 # empty ranges begin at line just before the range + return '{},{}'.format(beginning, length) + def unified_diff(a, b, fromfile='', tofile='', fromfiledate='', tofiledate='', n=3, lineterm='\n'): r""" @@ -1193,9 +1204,12 @@ todate = '\t{}'.format(tofiledate) if tofiledate else '' yield '--- {}{}{}'.format(fromfile, fromdate, lineterm) yield '+++ {}{}{}'.format(tofile, todate, lineterm) + first, last = group[0], group[-1] - i1, i2, j1, j2 = first[1], last[2], first[3], last[4] - yield '@@ -{},{} +{},{} @@{}'.format(i1+1, i2-i1, j1+1, j2-j1, lineterm) + file1_range = _format_range(first[1], last[2]) + file2_range = _format_range(first[3], last[4]) + yield '@@ -{} +{} @@{}'.format(file1_range, file2_range, lineterm) + for tag, i1, i2, j1, j2 in group: if tag == 'equal': for line in a[i1:i2]: @@ -1264,22 +1278,20 @@ yield '--- {}{}{}'.format(tofile, todate, lineterm) first, last = group[0], group[-1] - yield '***************{}'.format(lineterm) + yield '***************' + lineterm - if last[2] - first[1] > 1: - yield '*** {},{} ****{}'.format(first[1]+1, last[2], lineterm) - else: - yield '*** {} ****{}'.format(last[2], lineterm) + file1_range = _format_range(first[1], last[2]) + yield '*** {} ****{}'.format(file1_range, lineterm) + if any(tag in {'replace', 'delete'} for tag, _, _, _, _ in group): for tag, i1, i2, _, _ in group: if tag != 'insert': for line in a[i1:i2]: yield prefix[tag] + line - if last[4] - first[3] > 1: - yield '--- {},{} ----{}'.format(first[3]+1, last[4], lineterm) - else: - yield '--- {} ----{}'.format(last[4], lineterm) + file2_range = _format_range(first[3], last[4]) + yield '--- {} ----{}'.format(file2_range, lineterm) + if any(tag in {'replace', 'insert'} for tag, _, _, _, _ in group): for tag, _, _, j1, j2 in group: if tag != 'delete': diff --git a/Lib/test/test_difflib.py b/Lib/test/test_difflib.py --- a/Lib/test/test_difflib.py +++ b/Lib/test/test_difflib.py @@ -236,6 +236,22 @@ cd = difflib.context_diff(*args, lineterm='') self.assertEqual(list(cd)[0:2], ["*** Original", "--- Current"]) + def test_range_format(self): + # Per the diff spec at http://www.unix.org/single_unix_specification/ + spec = '''\ + Each field shall be of the form: + %1d", if the range contains exactly one line, + and: + "%1d,%1d", , otherwise. + If a range is empty, its beginning line number shall be the number of + the line just before the range, or 0 if the empty range starts the file. + ''' + fmt = difflib._format_range + self.assertEqual(fmt(3,3), '3,0') + self.assertEqual(fmt(3,4), '4') + self.assertEqual(fmt(3,5), '4,2') + self.assertEqual(fmt(3,6), '4,3') + self.assertEqual(fmt(0,0), '0,0') def test_main(): difflib.HtmlDiff._default_prefix = 0 diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -109,6 +109,9 @@ - Issue #11814: Fix likely typo in multiprocessing.Pool._terminate(). +- Issue #11747: Fix range formatting in difflib.context_diff() and + difflib.unified_diff(). + - Issue #8428: Fix a race condition in multiprocessing.Pool when terminating worker processes: new processes would be spawned while the pool is being shut down. Patch by Charles-Fran?ois Natali. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 12 01:01:36 2011 From: python-checkins at python.org (brian.curtin) Date: Tue, 12 Apr 2011 01:01:36 +0200 Subject: [Python-checkins] cpython (3.1): Fix #5162. Allow child spawning from Windows services (via pywin32). Message-ID: http://hg.python.org/cpython/rev/1f41b1ab8924 changeset: 69252:1f41b1ab8924 branch: 3.1 parent: 69225:42d5001e5845 user: brian.curtin date: Mon Apr 11 17:56:23 2011 -0500 summary: Fix #5162. Allow child spawning from Windows services (via pywin32). files: Lib/multiprocessing/forking.py | 5 +++-- 1 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Lib/multiprocessing/forking.py b/Lib/multiprocessing/forking.py --- a/Lib/multiprocessing/forking.py +++ b/Lib/multiprocessing/forking.py @@ -195,6 +195,7 @@ TERMINATE = 0x10000 WINEXE = (sys.platform == 'win32' and getattr(sys, 'frozen', False)) + WINSERVICE = sys.executable.lower().endswith("pythonservice.exe") exit = win32.ExitProcess close = win32.CloseHandle @@ -204,7 +205,7 @@ # People embedding Python want to modify it. # - if sys.executable.lower().endswith('pythonservice.exe'): + if WINSERVICE: _python_exe = os.path.join(sys.exec_prefix, 'python.exe') else: _python_exe = sys.executable @@ -394,7 +395,7 @@ if _logger is not None: d['log_level'] = _logger.getEffectiveLevel() - if not WINEXE: + if not WINEXE and not WINSERVICE: main_path = getattr(sys.modules['__main__'], '__file__', None) if not main_path and sys.argv[0] not in ('', '-c'): main_path = sys.argv[0] -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 12 01:01:38 2011 From: python-checkins at python.org (brian.curtin) Date: Tue, 12 Apr 2011 01:01:38 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): Fix #5162. Allow child spawning from Windows services (via pywin32). Message-ID: http://hg.python.org/cpython/rev/184ae02e3221 changeset: 69253:184ae02e3221 branch: 3.2 parent: 69250:a2ee967de44f parent: 69252:1f41b1ab8924 user: brian.curtin date: Mon Apr 11 17:57:59 2011 -0500 summary: Fix #5162. Allow child spawning from Windows services (via pywin32). files: Lib/multiprocessing/forking.py | 5 +++-- 1 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Lib/multiprocessing/forking.py b/Lib/multiprocessing/forking.py --- a/Lib/multiprocessing/forking.py +++ b/Lib/multiprocessing/forking.py @@ -195,6 +195,7 @@ TERMINATE = 0x10000 WINEXE = (sys.platform == 'win32' and getattr(sys, 'frozen', False)) + WINSERVICE = sys.executable.lower().endswith("pythonservice.exe") exit = win32.ExitProcess close = win32.CloseHandle @@ -204,7 +205,7 @@ # People embedding Python want to modify it. # - if sys.executable.lower().endswith('pythonservice.exe'): + if WINSERVICE: _python_exe = os.path.join(sys.exec_prefix, 'python.exe') else: _python_exe = sys.executable @@ -394,7 +395,7 @@ if _logger is not None: d['log_level'] = _logger.getEffectiveLevel() - if not WINEXE: + if not WINEXE and not WINSERVICE: main_path = getattr(sys.modules['__main__'], '__file__', None) if not main_path and sys.argv[0] not in ('', '-c'): main_path = sys.argv[0] -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 12 01:01:40 2011 From: python-checkins at python.org (brian.curtin) Date: Tue, 12 Apr 2011 01:01:40 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Fix #5162. Allow child spawning from Windows services (via pywin32). Message-ID: http://hg.python.org/cpython/rev/3c2bdea18b5c changeset: 69254:3c2bdea18b5c parent: 69251:1e5e3bb3e1f1 parent: 69253:184ae02e3221 user: brian.curtin date: Mon Apr 11 17:59:01 2011 -0500 summary: Fix #5162. Allow child spawning from Windows services (via pywin32). files: Lib/multiprocessing/forking.py | 5 +++-- 1 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Lib/multiprocessing/forking.py b/Lib/multiprocessing/forking.py --- a/Lib/multiprocessing/forking.py +++ b/Lib/multiprocessing/forking.py @@ -195,6 +195,7 @@ TERMINATE = 0x10000 WINEXE = (sys.platform == 'win32' and getattr(sys, 'frozen', False)) + WINSERVICE = sys.executable.lower().endswith("pythonservice.exe") exit = win32.ExitProcess close = win32.CloseHandle @@ -204,7 +205,7 @@ # People embedding Python want to modify it. # - if sys.executable.lower().endswith('pythonservice.exe'): + if WINSERVICE: _python_exe = os.path.join(sys.exec_prefix, 'python.exe') else: _python_exe = sys.executable @@ -394,7 +395,7 @@ if _logger is not None: d['log_level'] = _logger.getEffectiveLevel() - if not WINEXE: + if not WINEXE and not WINSERVICE: main_path = getattr(sys.modules['__main__'], '__file__', None) if not main_path and sys.argv[0] not in ('', '-c'): main_path = sys.argv[0] -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 12 01:01:42 2011 From: python-checkins at python.org (brian.curtin) Date: Tue, 12 Apr 2011 01:01:42 +0200 Subject: [Python-checkins] cpython (2.7): Fix #5162. Allow child spawning from Windows services (via pywin32). Message-ID: http://hg.python.org/cpython/rev/6507a5ba5c27 changeset: 69255:6507a5ba5c27 branch: 2.7 parent: 69244:ba699cf9bdbb user: brian.curtin date: Mon Apr 11 18:00:59 2011 -0500 summary: Fix #5162. Allow child spawning from Windows services (via pywin32). files: Lib/multiprocessing/forking.py | 5 +++-- 1 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Lib/multiprocessing/forking.py b/Lib/multiprocessing/forking.py --- a/Lib/multiprocessing/forking.py +++ b/Lib/multiprocessing/forking.py @@ -198,6 +198,7 @@ TERMINATE = 0x10000 WINEXE = (sys.platform == 'win32' and getattr(sys, 'frozen', False)) + WINSERVICE = sys.executable.lower().endswith("pythonservice.exe") exit = win32.ExitProcess close = win32.CloseHandle @@ -207,7 +208,7 @@ # People embedding Python want to modify it. # - if sys.executable.lower().endswith('pythonservice.exe'): + if WINSERVICE: _python_exe = os.path.join(sys.exec_prefix, 'python.exe') else: _python_exe = sys.executable @@ -397,7 +398,7 @@ if _logger is not None: d['log_level'] = _logger.getEffectiveLevel() - if not WINEXE: + if not WINEXE and not WINSERVICE: main_path = getattr(sys.modules['__main__'], '__file__', None) if not main_path and sys.argv[0] not in ('', '-c'): main_path = sys.argv[0] -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 12 01:06:56 2011 From: python-checkins at python.org (brian.curtin) Date: Tue, 12 Apr 2011 01:06:56 +0200 Subject: [Python-checkins] cpython (2.7): Add NEWS item for #5162. Message-ID: http://hg.python.org/cpython/rev/a280672d3d8d changeset: 69256:a280672d3d8d branch: 2.7 user: brian.curtin date: Mon Apr 11 18:05:33 2011 -0500 summary: Add NEWS item for #5162. files: Misc/NEWS | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -51,6 +51,9 @@ Library ------- +- Issue #5162: Treat services like frozen executables to allow child spawning + from multiprocessing.forking on Windows. + - Issue #4877: Fix a segfault in xml.parsers.expat while attempting to parse a closed file. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 12 01:20:07 2011 From: python-checkins at python.org (brian.curtin) Date: Tue, 12 Apr 2011 01:20:07 +0200 Subject: [Python-checkins] cpython (3.1): Add NEWS item for #5162. Message-ID: http://hg.python.org/cpython/rev/c26474c6504a changeset: 69257:c26474c6504a branch: 3.1 parent: 69252:1f41b1ab8924 user: brian.curtin date: Mon Apr 11 18:09:24 2011 -0500 summary: Add NEWS item for #5162. files: Misc/NEWS | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -48,6 +48,9 @@ Library ------- + - Issue #5162: Treat services like frozen executables to allow child spawning + from multiprocessing.forking on Windows. + - Issue #10963: Ensure that subprocess.communicate() never raises EPIPE. - Issue #11696: Fix ID generation in msilib. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 12 01:20:08 2011 From: python-checkins at python.org (brian.curtin) Date: Tue, 12 Apr 2011 01:20:08 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): Add NEWS item for #5162. Message-ID: http://hg.python.org/cpython/rev/68ef2bf1aa99 changeset: 69258:68ef2bf1aa99 branch: 3.2 parent: 69253:184ae02e3221 parent: 69257:c26474c6504a user: brian.curtin date: Mon Apr 11 18:18:20 2011 -0500 summary: Add NEWS item for #5162. files: Misc/NEWS | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -53,6 +53,9 @@ Library ------- +- Issue #5162: Treat services like frozen executables to allow child spawning + from multiprocessing.forking on Windows. + - Issue #11814: Fix likely typo in multiprocessing.Pool._terminate(). - Issue #11747: Fix range formatting in difflib.context_diff() and -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 12 01:20:09 2011 From: python-checkins at python.org (brian.curtin) Date: Tue, 12 Apr 2011 01:20:09 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Add NEWS item for #5162. Message-ID: http://hg.python.org/cpython/rev/2c4043070f05 changeset: 69259:2c4043070f05 parent: 69254:3c2bdea18b5c parent: 69258:68ef2bf1aa99 user: brian.curtin date: Mon Apr 11 18:19:38 2011 -0500 summary: Add NEWS item for #5162. files: Misc/NEWS | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -103,6 +103,9 @@ Library ------- +- Issue #5162: Treat services like frozen executables to allow child spawning + from multiprocessing.forking on Windows. + - logging.basicConfig now supports an optional 'handlers' argument taking an iterable of handlers to be added to the root logger. Additional parameter checks were also added to basicConfig. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 12 01:37:27 2011 From: python-checkins at python.org (brian.curtin) Date: Tue, 12 Apr 2011 01:37:27 +0200 Subject: [Python-checkins] cpython (3.1): Correct leading spaces in my NEWS entry. Message-ID: http://hg.python.org/cpython/rev/33b54387cc2a changeset: 69260:33b54387cc2a branch: 3.1 parent: 69257:c26474c6504a user: Brian Curtin date: Mon Apr 11 18:35:18 2011 -0500 summary: Correct leading spaces in my NEWS entry. files: Misc/NEWS | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -48,8 +48,8 @@ Library ------- - - Issue #5162: Treat services like frozen executables to allow child spawning - from multiprocessing.forking on Windows. +- Issue #5162: Treat services like frozen executables to allow child spawning + from multiprocessing.forking on Windows. - Issue #10963: Ensure that subprocess.communicate() never raises EPIPE. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 12 01:37:27 2011 From: python-checkins at python.org (brian.curtin) Date: Tue, 12 Apr 2011 01:37:27 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): Dummy merge Message-ID: http://hg.python.org/cpython/rev/b166c972cb5e changeset: 69261:b166c972cb5e branch: 3.2 parent: 69258:68ef2bf1aa99 parent: 69260:33b54387cc2a user: Brian Curtin date: Mon Apr 11 18:36:25 2011 -0500 summary: Dummy merge files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 12 01:37:28 2011 From: python-checkins at python.org (brian.curtin) Date: Tue, 12 Apr 2011 01:37:28 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Dummy merge Message-ID: http://hg.python.org/cpython/rev/5062b5286eba changeset: 69262:5062b5286eba parent: 69259:2c4043070f05 parent: 69261:b166c972cb5e user: Brian Curtin date: Mon Apr 11 18:36:59 2011 -0500 summary: Dummy merge files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 12 02:28:02 2011 From: python-checkins at python.org (raymond.hettinger) Date: Tue, 12 Apr 2011 02:28:02 +0200 Subject: [Python-checkins] cpython (2.7): Issue #11830: Remove unnecessary introspection code in the decimal module. Message-ID: http://hg.python.org/cpython/rev/b4b1f557d563 changeset: 69263:b4b1f557d563 branch: 2.7 parent: 69256:a280672d3d8d user: Raymond Hettinger date: Mon Apr 11 17:27:42 2011 -0700 summary: Issue #11830: Remove unnecessary introspection code in the decimal module. It was causing a failed import in the Turkish locale where the locale sensitive str.upper() method caused a name mismatch. files: Lib/decimal.py | 25 +++++++++++-------------- Misc/NEWS | 4 ++++ 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/Lib/decimal.py b/Lib/decimal.py --- a/Lib/decimal.py +++ b/Lib/decimal.py @@ -1723,8 +1723,6 @@ # here self was representable to begin with; return unchanged return Decimal(self) - _pick_rounding_function = {} - # for each of the rounding functions below: # self is a finite, nonzero Decimal # prec is an integer satisfying 0 <= prec < len(self._int) @@ -1791,6 +1789,17 @@ else: return -self._round_down(prec) + _pick_rounding_function = dict( + ROUND_DOWN = '_round_down', + ROUND_UP = '_round_up', + ROUND_HALF_UP = '_round_half_up', + ROUND_HALF_DOWN = '_round_half_down', + ROUND_HALF_EVEN = '_round_half_even', + ROUND_CEILING = '_round_ceiling', + ROUND_FLOOR = '_round_floor', + ROUND_05UP = '_round_05up', + ) + def fma(self, other, third, context=None): """Fused multiply-add. @@ -3708,18 +3717,6 @@ ##### Context class ####################################################### - -# get rounding method function: -rounding_functions = [name for name in Decimal.__dict__.keys() - if name.startswith('_round_')] -for name in rounding_functions: - # name is like _round_half_even, goes to the global ROUND_HALF_EVEN value. - globalname = name[1:].upper() - val = globals()[globalname] - Decimal._pick_rounding_function[val] = name - -del name, val, globalname, rounding_functions - class _ContextManager(object): """Context manager class to support localcontext(). diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -57,6 +57,10 @@ - Issue #4877: Fix a segfault in xml.parsers.expat while attempting to parse a closed file. +- Issue #11830: Remove unnecessary introspection code in the decimal module. + It was causing a failed import in the Turkish locale where the locale + sensitive str.upper() method caused a name mismatch. + - Issue #8428: Fix a race condition in multiprocessing.Pool when terminating worker processes: new processes would be spawned while the pool is being shut down. Patch by Charles-Fran?ois Natali. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 12 02:45:14 2011 From: python-checkins at python.org (raymond.hettinger) Date: Tue, 12 Apr 2011 02:45:14 +0200 Subject: [Python-checkins] cpython (2.7): Use floor division operator instead of deprecated division operator. Message-ID: http://hg.python.org/cpython/rev/7b71872fb66a changeset: 69264:7b71872fb66a branch: 2.7 user: Raymond Hettinger date: Mon Apr 11 17:45:01 2011 -0700 summary: Use floor division operator instead of deprecated division operator. files: Lib/trace.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/trace.py b/Lib/trace.py --- a/Lib/trace.py +++ b/Lib/trace.py @@ -335,7 +335,7 @@ lnotab, count) if summary and n_lines: - percent = int(100 * n_hits / n_lines) + percent = 100 * n_hits // n_lines sums[modulename] = n_lines, percent, modulename, filename if summary and sums: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 12 02:57:50 2011 From: python-checkins at python.org (raymond.hettinger) Date: Tue, 12 Apr 2011 02:57:50 +0200 Subject: [Python-checkins] cpython: Fix markup. Message-ID: http://hg.python.org/cpython/rev/5e87dd117f74 changeset: 69265:5e87dd117f74 parent: 69262:5062b5286eba user: Raymond Hettinger date: Mon Apr 11 17:57:21 2011 -0700 summary: Fix markup. files: Doc/library/collections.rst | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/collections.rst b/Doc/library/collections.rst --- a/Doc/library/collections.rst +++ b/Doc/library/collections.rst @@ -60,9 +60,9 @@ Lookups search the underlying mappings successively until a key is found. In contrast, writes, updates, and deletions only operate on the first mapping. - A class:`ChainMap` incorporates the underlying mappings by reference. So, if + A :class:`ChainMap` incorporates the underlying mappings by reference. So, if one of the underlying mappings gets updated, those changes will be reflected - in class:`ChainMap`. + in :class:`ChainMap`. All of the usual dictionary methods are supported. In addition, there is a *maps* attribute, a method for creating new subcontexts, and a property for -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Tue Apr 12 05:00:07 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Tue, 12 Apr 2011 05:00:07 +0200 Subject: [Python-checkins] Daily reference leaks (5e87dd117f74): sum=-56 Message-ID: results for 5e87dd117f74 on branch "default" -------------------------------------------- test_pyexpat leaked [0, 0, -56] references, sum=-56 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/refloghaBAAf', '-x'] From nnorwitz at gmail.com Tue Apr 12 12:49:28 2011 From: nnorwitz at gmail.com (Neal Norwitz) Date: Tue, 12 Apr 2011 06:49:28 -0400 Subject: [Python-checkins] Python Regression Test Failures refleak (1) Message-ID: <20110412104928.GA11036@kbk-i386-bb.dyndns.org> More important issues: ---------------------- test_bz2 leaked [-84, 0, 0] references, sum=-84 Less important issues: ---------------------- From python-checkins at python.org Tue Apr 12 15:07:27 2011 From: python-checkins at python.org (ezio.melotti) Date: Tue, 12 Apr 2011 15:07:27 +0200 Subject: [Python-checkins] cpython (2.7): #9233: skip _json-specific tests when _json is not available. Message-ID: http://hg.python.org/cpython/rev/500063f6ae5a changeset: 69266:500063f6ae5a branch: 2.7 parent: 69264:7b71872fb66a user: Ezio Melotti date: Tue Apr 12 15:59:50 2011 +0300 summary: #9233: skip _json-specific tests when _json is not available. files: Lib/json/tests/test_scanstring.py | 8 +++++++- Lib/json/tests/test_speedups.py | 8 +++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/Lib/json/tests/test_scanstring.py b/Lib/json/tests/test_scanstring.py --- a/Lib/json/tests/test_scanstring.py +++ b/Lib/json/tests/test_scanstring.py @@ -1,14 +1,20 @@ import sys import decimal -from unittest import TestCase +from unittest import TestCase, skipUnless import json import json.decoder +try: + import _json +except ImportError: + _json = None + class TestScanString(TestCase): def test_py_scanstring(self): self._test_scanstring(json.decoder.py_scanstring) + @skipUnless(_json, 'test requires the _json module') def test_c_scanstring(self): self._test_scanstring(json.decoder.c_scanstring) diff --git a/Lib/json/tests/test_speedups.py b/Lib/json/tests/test_speedups.py --- a/Lib/json/tests/test_speedups.py +++ b/Lib/json/tests/test_speedups.py @@ -1,8 +1,14 @@ import decimal -from unittest import TestCase +from unittest import TestCase, skipUnless from json import decoder, encoder, scanner +try: + import _json +except ImportError: + _json = None + + at skipUnless(_json, 'test requires the _json module') class TestSpeedups(TestCase): def test_scanstring(self): self.assertEqual(decoder.scanstring.__module__, "_json") -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 12 15:07:29 2011 From: python-checkins at python.org (ezio.melotti) Date: Tue, 12 Apr 2011 15:07:29 +0200 Subject: [Python-checkins] cpython (2.7): Remove unnecessary imports and use assertIs instead of assertTrue. Message-ID: http://hg.python.org/cpython/rev/61f25c9e7fa1 changeset: 69267:61f25c9e7fa1 branch: 2.7 user: Ezio Melotti date: Tue Apr 12 16:06:43 2011 +0300 summary: Remove unnecessary imports and use assertIs instead of assertTrue. files: Lib/json/tests/test_scanstring.py | 1 - Lib/json/tests/test_speedups.py | 7 +++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/Lib/json/tests/test_scanstring.py b/Lib/json/tests/test_scanstring.py --- a/Lib/json/tests/test_scanstring.py +++ b/Lib/json/tests/test_scanstring.py @@ -1,5 +1,4 @@ import sys -import decimal from unittest import TestCase, skipUnless import json diff --git a/Lib/json/tests/test_speedups.py b/Lib/json/tests/test_speedups.py --- a/Lib/json/tests/test_speedups.py +++ b/Lib/json/tests/test_speedups.py @@ -1,4 +1,3 @@ -import decimal from unittest import TestCase, skipUnless from json import decoder, encoder, scanner @@ -12,12 +11,12 @@ class TestSpeedups(TestCase): def test_scanstring(self): self.assertEqual(decoder.scanstring.__module__, "_json") - self.assertTrue(decoder.scanstring is decoder.c_scanstring) + self.assertIs(decoder.scanstring, decoder.c_scanstring) def test_encode_basestring_ascii(self): self.assertEqual(encoder.encode_basestring_ascii.__module__, "_json") - self.assertTrue(encoder.encode_basestring_ascii is - encoder.c_encode_basestring_ascii) + self.assertIs(encoder.encode_basestring_ascii, + encoder.c_encode_basestring_ascii) class TestDecode(TestCase): def test_make_scanner(self): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 12 17:50:27 2011 From: python-checkins at python.org (antoine.pitrou) Date: Tue, 12 Apr 2011 17:50:27 +0200 Subject: [Python-checkins] cpython (3.2): Issue #11815: Remove dead code in concurrent.futures (since a blocking Queue Message-ID: http://hg.python.org/cpython/rev/bfc586c558ed changeset: 69268:bfc586c558ed branch: 3.2 parent: 69261:b166c972cb5e user: Antoine Pitrou date: Tue Apr 12 17:48:46 2011 +0200 summary: Issue #11815: Remove dead code in concurrent.futures (since a blocking Queue cannot raise queue.Empty). files: Lib/concurrent/futures/process.py | 67 ++++++------------ Lib/concurrent/futures/thread.py | 12 +-- 2 files changed, 28 insertions(+), 51 deletions(-) diff --git a/Lib/concurrent/futures/process.py b/Lib/concurrent/futures/process.py --- a/Lib/concurrent/futures/process.py +++ b/Lib/concurrent/futures/process.py @@ -104,7 +104,7 @@ self.args = args self.kwargs = kwargs -def _process_worker(call_queue, result_queue, shutdown): +def _process_worker(call_queue, result_queue): """Evaluates calls from call_queue and places the results in result_queue. This worker is run in a separate process. @@ -118,24 +118,19 @@ worker that it should exit when call_queue is empty. """ while True: + call_item = call_queue.get(block=True) + if call_item is None: + # Wake up queue management thread + result_queue.put(None) + return try: - call_item = call_queue.get(block=True) - except queue.Empty: - if shutdown.is_set(): - return + r = call_item.fn(*call_item.args, **call_item.kwargs) + except BaseException as e: + result_queue.put(_ResultItem(call_item.work_id, + exception=e)) else: - if call_item is None: - # Wake up queue management thread - result_queue.put(None) - return - try: - r = call_item.fn(*call_item.args, **call_item.kwargs) - except BaseException as e: - result_queue.put(_ResultItem(call_item.work_id, - exception=e)) - else: - result_queue.put(_ResultItem(call_item.work_id, - result=r)) + result_queue.put(_ResultItem(call_item.work_id, + result=r)) def _add_call_item_to_queue(pending_work_items, work_ids, @@ -179,8 +174,7 @@ pending_work_items, work_ids_queue, call_queue, - result_queue, - shutdown_process_event): + result_queue): """Manages the communication between this process and the worker processes. This function is run in a local thread. @@ -198,9 +192,6 @@ derived from _WorkItems for processing by the process workers. result_queue: A multiprocessing.Queue of _ResultItems generated by the process workers. - shutdown_process_event: A multiprocessing.Event used to signal the - process workers that they should exit when their work queue is - empty. """ nb_shutdown_processes = 0 def shutdown_one_process(): @@ -213,20 +204,16 @@ work_ids_queue, call_queue) - try: - result_item = result_queue.get(block=True) - except queue.Empty: - pass - else: - if result_item is not None: - work_item = pending_work_items[result_item.work_id] - del pending_work_items[result_item.work_id] + result_item = result_queue.get(block=True) + if result_item is not None: + work_item = pending_work_items[result_item.work_id] + del pending_work_items[result_item.work_id] - if result_item.exception: - work_item.future.set_exception(result_item.exception) - else: - work_item.future.set_result(result_item.result) - continue + if result_item.exception: + work_item.future.set_exception(result_item.exception) + else: + work_item.future.set_result(result_item.result) + continue # If we come here, we either got a timeout or were explicitly woken up. # In either case, check whether we should start shutting down. executor = executor_reference() @@ -238,8 +225,6 @@ # Since no new work items can be added, it is safe to shutdown # this thread if there are no pending work items. if not pending_work_items: - shutdown_process_event.set() - while nb_shutdown_processes < len(processes): shutdown_one_process() # If .join() is not called on the created processes then @@ -306,7 +291,6 @@ # Shutdown is a two-step process. self._shutdown_thread = False - self._shutdown_process_event = multiprocessing.Event() self._shutdown_lock = threading.Lock() self._queue_count = 0 self._pending_work_items = {} @@ -324,8 +308,7 @@ self._pending_work_items, self._work_ids, self._call_queue, - self._result_queue, - self._shutdown_process_event)) + self._result_queue)) self._queue_management_thread.daemon = True self._queue_management_thread.start() _threads_queues[self._queue_management_thread] = self._result_queue @@ -335,8 +318,7 @@ p = multiprocessing.Process( target=_process_worker, args=(self._call_queue, - self._result_queue, - self._shutdown_process_event)) + self._result_queue)) p.start() self._processes.add(p) @@ -372,7 +354,6 @@ self._queue_management_thread = None self._call_queue = None self._result_queue = None - self._shutdown_process_event = None self._processes = None shutdown.__doc__ = _base.Executor.shutdown.__doc__ diff --git a/Lib/concurrent/futures/thread.py b/Lib/concurrent/futures/thread.py --- a/Lib/concurrent/futures/thread.py +++ b/Lib/concurrent/futures/thread.py @@ -60,14 +60,10 @@ def _worker(executor_reference, work_queue): try: while True: - try: - work_item = work_queue.get(block=True) - except queue.Empty: - pass - else: - if work_item is not None: - work_item.run() - continue + work_item = work_queue.get(block=True) + if work_item is not None: + work_item.run() + continue executor = executor_reference() # Exit if: # - The interpreter is shutting down OR -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 12 17:50:31 2011 From: python-checkins at python.org (antoine.pitrou) Date: Tue, 12 Apr 2011 17:50:31 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Issue #11815: Remove dead code in concurrent.futures (since a blocking Queue Message-ID: http://hg.python.org/cpython/rev/eb751e3cb753 changeset: 69269:eb751e3cb753 parent: 69265:5e87dd117f74 parent: 69268:bfc586c558ed user: Antoine Pitrou date: Tue Apr 12 17:50:20 2011 +0200 summary: Issue #11815: Remove dead code in concurrent.futures (since a blocking Queue cannot raise queue.Empty). files: Lib/concurrent/futures/process.py | 67 ++++++------------ Lib/concurrent/futures/thread.py | 12 +-- 2 files changed, 28 insertions(+), 51 deletions(-) diff --git a/Lib/concurrent/futures/process.py b/Lib/concurrent/futures/process.py --- a/Lib/concurrent/futures/process.py +++ b/Lib/concurrent/futures/process.py @@ -104,7 +104,7 @@ self.args = args self.kwargs = kwargs -def _process_worker(call_queue, result_queue, shutdown): +def _process_worker(call_queue, result_queue): """Evaluates calls from call_queue and places the results in result_queue. This worker is run in a separate process. @@ -118,24 +118,19 @@ worker that it should exit when call_queue is empty. """ while True: + call_item = call_queue.get(block=True) + if call_item is None: + # Wake up queue management thread + result_queue.put(None) + return try: - call_item = call_queue.get(block=True) - except queue.Empty: - if shutdown.is_set(): - return + r = call_item.fn(*call_item.args, **call_item.kwargs) + except BaseException as e: + result_queue.put(_ResultItem(call_item.work_id, + exception=e)) else: - if call_item is None: - # Wake up queue management thread - result_queue.put(None) - return - try: - r = call_item.fn(*call_item.args, **call_item.kwargs) - except BaseException as e: - result_queue.put(_ResultItem(call_item.work_id, - exception=e)) - else: - result_queue.put(_ResultItem(call_item.work_id, - result=r)) + result_queue.put(_ResultItem(call_item.work_id, + result=r)) def _add_call_item_to_queue(pending_work_items, work_ids, @@ -179,8 +174,7 @@ pending_work_items, work_ids_queue, call_queue, - result_queue, - shutdown_process_event): + result_queue): """Manages the communication between this process and the worker processes. This function is run in a local thread. @@ -198,9 +192,6 @@ derived from _WorkItems for processing by the process workers. result_queue: A multiprocessing.Queue of _ResultItems generated by the process workers. - shutdown_process_event: A multiprocessing.Event used to signal the - process workers that they should exit when their work queue is - empty. """ nb_shutdown_processes = 0 def shutdown_one_process(): @@ -213,20 +204,16 @@ work_ids_queue, call_queue) - try: - result_item = result_queue.get(block=True) - except queue.Empty: - pass - else: - if result_item is not None: - work_item = pending_work_items[result_item.work_id] - del pending_work_items[result_item.work_id] + result_item = result_queue.get(block=True) + if result_item is not None: + work_item = pending_work_items[result_item.work_id] + del pending_work_items[result_item.work_id] - if result_item.exception: - work_item.future.set_exception(result_item.exception) - else: - work_item.future.set_result(result_item.result) - continue + if result_item.exception: + work_item.future.set_exception(result_item.exception) + else: + work_item.future.set_result(result_item.result) + continue # If we come here, we either got a timeout or were explicitly woken up. # In either case, check whether we should start shutting down. executor = executor_reference() @@ -238,8 +225,6 @@ # Since no new work items can be added, it is safe to shutdown # this thread if there are no pending work items. if not pending_work_items: - shutdown_process_event.set() - while nb_shutdown_processes < len(processes): shutdown_one_process() # If .join() is not called on the created processes then @@ -306,7 +291,6 @@ # Shutdown is a two-step process. self._shutdown_thread = False - self._shutdown_process_event = multiprocessing.Event() self._shutdown_lock = threading.Lock() self._queue_count = 0 self._pending_work_items = {} @@ -324,8 +308,7 @@ self._pending_work_items, self._work_ids, self._call_queue, - self._result_queue, - self._shutdown_process_event)) + self._result_queue)) self._queue_management_thread.daemon = True self._queue_management_thread.start() _threads_queues[self._queue_management_thread] = self._result_queue @@ -335,8 +318,7 @@ p = multiprocessing.Process( target=_process_worker, args=(self._call_queue, - self._result_queue, - self._shutdown_process_event)) + self._result_queue)) p.start() self._processes.add(p) @@ -372,7 +354,6 @@ self._queue_management_thread = None self._call_queue = None self._result_queue = None - self._shutdown_process_event = None self._processes = None shutdown.__doc__ = _base.Executor.shutdown.__doc__ diff --git a/Lib/concurrent/futures/thread.py b/Lib/concurrent/futures/thread.py --- a/Lib/concurrent/futures/thread.py +++ b/Lib/concurrent/futures/thread.py @@ -60,14 +60,10 @@ def _worker(executor_reference, work_queue): try: while True: - try: - work_item = work_queue.get(block=True) - except queue.Empty: - pass - else: - if work_item is not None: - work_item.run() - continue + work_item = work_queue.get(block=True) + if work_item is not None: + work_item.run() + continue executor = executor_reference() # Exit if: # - The interpreter is shutting down OR -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 12 17:58:16 2011 From: python-checkins at python.org (antoine.pitrou) Date: Tue, 12 Apr 2011 17:58:16 +0200 Subject: [Python-checkins] cpython: Issue #11815: Use a light-weight SimpleQueue for the result queue in Message-ID: http://hg.python.org/cpython/rev/c26d015cbde8 changeset: 69270:c26d015cbde8 user: Antoine Pitrou date: Tue Apr 12 17:58:11 2011 +0200 summary: Issue #11815: Use a light-weight SimpleQueue for the result queue in concurrent.futures.ProcessPoolExecutor. files: Lib/concurrent/futures/process.py | 5 +++-- Misc/NEWS | 3 +++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Lib/concurrent/futures/process.py b/Lib/concurrent/futures/process.py --- a/Lib/concurrent/futures/process.py +++ b/Lib/concurrent/futures/process.py @@ -49,6 +49,7 @@ from concurrent.futures import _base import queue import multiprocessing +from multiprocessing.queues import SimpleQueue import threading import weakref @@ -204,7 +205,7 @@ work_ids_queue, call_queue) - result_item = result_queue.get(block=True) + result_item = result_queue.get() if result_item is not None: work_item = pending_work_items[result_item.work_id] del pending_work_items[result_item.work_id] @@ -284,7 +285,7 @@ # because futures in the call queue cannot be cancelled. self._call_queue = multiprocessing.Queue(self._max_workers + EXTRA_QUEUED_CALLS) - self._result_queue = multiprocessing.Queue() + self._result_queue = SimpleQueue() self._work_ids = queue.Queue() self._queue_management_thread = None self._processes = set() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -103,6 +103,9 @@ Library ------- +- Issue #11815: Use a light-weight SimpleQueue for the result queue in + concurrent.futures.ProcessPoolExecutor. + - Issue #5162: Treat services like frozen executables to allow child spawning from multiprocessing.forking on Windows. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 12 18:06:10 2011 From: python-checkins at python.org (raymond.hettinger) Date: Tue, 12 Apr 2011 18:06:10 +0200 Subject: [Python-checkins] cpython (2.7): Neaten-up the fix to issue 11830 Message-ID: http://hg.python.org/cpython/rev/f4adc2926bf5 changeset: 69271:f4adc2926bf5 branch: 2.7 parent: 69267:61f25c9e7fa1 user: Raymond Hettinger date: Tue Apr 12 09:06:01 2011 -0700 summary: Neaten-up the fix to issue 11830 files: Lib/decimal.py | 22 +++++++++++----------- 1 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Lib/decimal.py b/Lib/decimal.py --- a/Lib/decimal.py +++ b/Lib/decimal.py @@ -1683,7 +1683,7 @@ self = _dec_from_triple(self._sign, '1', exp_min-1) digits = 0 rounding_method = self._pick_rounding_function[context.rounding] - changed = getattr(self, rounding_method)(digits) + changed = rounding_method(self, digits) coeff = self._int[:digits] or '0' if changed > 0: coeff = str(int(coeff)+1) @@ -1790,14 +1790,14 @@ return -self._round_down(prec) _pick_rounding_function = dict( - ROUND_DOWN = '_round_down', - ROUND_UP = '_round_up', - ROUND_HALF_UP = '_round_half_up', - ROUND_HALF_DOWN = '_round_half_down', - ROUND_HALF_EVEN = '_round_half_even', - ROUND_CEILING = '_round_ceiling', - ROUND_FLOOR = '_round_floor', - ROUND_05UP = '_round_05up', + ROUND_DOWN = _round_down, + ROUND_UP = _round_up, + ROUND_HALF_UP = _round_half_up, + ROUND_HALF_DOWN = _round_half_down, + ROUND_HALF_EVEN = _round_half_even, + ROUND_CEILING = _round_ceiling, + ROUND_FLOOR = _round_floor, + ROUND_05UP = _round_05up, ) def fma(self, other, third, context=None): @@ -2504,8 +2504,8 @@ if digits < 0: self = _dec_from_triple(self._sign, '1', exp-1) digits = 0 - this_function = getattr(self, self._pick_rounding_function[rounding]) - changed = this_function(digits) + this_function = self._pick_rounding_function[rounding] + changed = this_function(self, digits) coeff = self._int[:digits] or '0' if changed == 1: coeff = str(int(coeff)+1) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 12 21:03:14 2011 From: python-checkins at python.org (r.david.murray) Date: Tue, 12 Apr 2011 21:03:14 +0200 Subject: [Python-checkins] cpython (3.1): Add maxlinelen to docstring, delete obsolete wording Message-ID: http://hg.python.org/cpython/rev/f9bd0add9732 changeset: 69272:f9bd0add9732 branch: 3.1 parent: 69260:33b54387cc2a user: R David Murray date: Tue Apr 12 15:00:44 2011 -0400 summary: Add maxlinelen to docstring, delete obsolete wording files: Lib/email/header.py | 12 ++++++------ 1 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Lib/email/header.py b/Lib/email/header.py --- a/Lib/email/header.py +++ b/Lib/email/header.py @@ -281,12 +281,12 @@ 75-character length limit on any given encoded header field, so line-wrapping must be performed, even with double-byte character sets. - This method will do its best to convert the string to the correct - character set used in email, and encode and line wrap it safely with - the appropriate scheme for that character set. - - If the given charset is not known or an error occurs during - conversion, this function will return the header untouched. + Optional maxlinelen specifies the maxiumum length of each generated + line, exclusive of the linesep string. Individual lines may be longer + than maxlinelen if a folding point cannot be found. The first line + will be shorter by the length of the header name plus ": " if a header + name was specified at Header construction time. The default value for + maxlinelen is determined at header construction time. Optional splitchars is a string containing characters to split long ASCII lines on, in rough support of RFC 2822's `highest level -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 12 21:03:17 2011 From: python-checkins at python.org (r.david.murray) Date: Tue, 12 Apr 2011 21:03:17 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): Merge: Add maxlinelen to docstring, delete obsolete wording Message-ID: http://hg.python.org/cpython/rev/4254085bae84 changeset: 69273:4254085bae84 branch: 3.2 parent: 69268:bfc586c558ed parent: 69272:f9bd0add9732 user: R David Murray date: Tue Apr 12 15:01:28 2011 -0400 summary: Merge: Add maxlinelen to docstring, delete obsolete wording files: Lib/email/header.py | 12 ++++++------ 1 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Lib/email/header.py b/Lib/email/header.py --- a/Lib/email/header.py +++ b/Lib/email/header.py @@ -292,12 +292,12 @@ 75-character length limit on any given encoded header field, so line-wrapping must be performed, even with double-byte character sets. - This method will do its best to convert the string to the correct - character set used in email, and encode and line wrap it safely with - the appropriate scheme for that character set. - - If the given charset is not known or an error occurs during - conversion, this function will return the header untouched. + Optional maxlinelen specifies the maxiumum length of each generated + line, exclusive of the linesep string. Individual lines may be longer + than maxlinelen if a folding point cannot be found. The first line + will be shorter by the length of the header name plus ": " if a header + name was specified at Header construction time. The default value for + maxlinelen is determined at header construction time. Optional splitchars is a string containing characters to split long ASCII lines on, in rough support of RFC 2822's `highest level -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 12 21:03:18 2011 From: python-checkins at python.org (r.david.murray) Date: Tue, 12 Apr 2011 21:03:18 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge: Add maxlinelen to docstring, delete obsolete wording Message-ID: http://hg.python.org/cpython/rev/66069ee12007 changeset: 69274:66069ee12007 parent: 69270:c26d015cbde8 parent: 69273:4254085bae84 user: R David Murray date: Tue Apr 12 15:02:07 2011 -0400 summary: Merge: Add maxlinelen to docstring, delete obsolete wording files: Lib/email/header.py | 12 ++++++------ 1 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Lib/email/header.py b/Lib/email/header.py --- a/Lib/email/header.py +++ b/Lib/email/header.py @@ -292,12 +292,12 @@ 75-character length limit on any given encoded header field, so line-wrapping must be performed, even with double-byte character sets. - This method will do its best to convert the string to the correct - character set used in email, and encode and line wrap it safely with - the appropriate scheme for that character set. - - If the given charset is not known or an error occurs during - conversion, this function will return the header untouched. + Optional maxlinelen specifies the maxiumum length of each generated + line, exclusive of the linesep string. Individual lines may be longer + than maxlinelen if a folding point cannot be found. The first line + will be shorter by the length of the header name plus ": " if a header + name was specified at Header construction time. The default value for + maxlinelen is determined at header construction time. Optional splitchars is a string containing characters to split long ASCII lines on, in rough support of RFC 2822's `highest level -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 12 23:05:40 2011 From: python-checkins at python.org (nadeem.vawda) Date: Tue, 12 Apr 2011 23:05:40 +0200 Subject: [Python-checkins] cpython: Fix 64-bit safety issue in BZ2Compressor and BZ2Decompressor. Message-ID: http://hg.python.org/cpython/rev/0010cc5f22d4 changeset: 69275:0010cc5f22d4 user: Nadeem Vawda date: Tue Apr 12 23:02:42 2011 +0200 summary: Fix 64-bit safety issue in BZ2Compressor and BZ2Decompressor. files: Lib/test/test_bz2.py | 36 +++++++++++++++++++++++++++++++- Modules/_bz2module.c | 33 +++++++++++++++++++++-------- 2 files changed, 59 insertions(+), 10 deletions(-) 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 @@ -1,10 +1,11 @@ #!/usr/bin/env python3 from test import support -from test.support import TESTFN +from test.support import TESTFN, precisionbigmemtest, _4G import unittest from io import BytesIO import os +import random import subprocess import sys @@ -415,6 +416,23 @@ data += bz2c.flush() self.assertEqual(self.decompress(data), self.TEXT) + @precisionbigmemtest(size=_4G + 100, memuse=2) + def testCompress4G(self, size): + # "Test BZ2Compressor.compress()/flush() with >4GiB input" + bz2c = BZ2Compressor() + data = b"x" * size + try: + compressed = bz2c.compress(data) + compressed += bz2c.flush() + finally: + data = None # Release memory + data = bz2.decompress(compressed) + try: + self.assertEqual(len(data), size) + self.assertEqual(len(data.strip(b"x")), 0) + finally: + data = None + class BZ2DecompressorTest(BaseTest): def test_Constructor(self): self.assertRaises(TypeError, BZ2Decompressor, 42) @@ -453,6 +471,22 @@ text = bz2d.decompress(self.DATA) self.assertRaises(EOFError, bz2d.decompress, b"anything") + @precisionbigmemtest(size=_4G + 100, memuse=3) + def testDecompress4G(self, size): + # "Test BZ2Decompressor.decompress() with >4GiB input" + blocksize = 10 * 1024 * 1024 + block = random.getrandbits(blocksize * 8).to_bytes(blocksize, 'little') + try: + data = block * (size // blocksize + 1) + compressed = bz2.compress(data) + bz2d = BZ2Decompressor() + decompressed = bz2d.decompress(compressed) + self.assertTrue(decompressed == data) + finally: + data = None + compressed = None + decompressed = None + class FuncTest(BaseTest): "Test module functions" diff --git a/Modules/_bz2module.c b/Modules/_bz2module.c --- a/Modules/_bz2module.c +++ b/Modules/_bz2module.c @@ -36,6 +36,8 @@ #define RELEASE_LOCK(obj) #endif +#define MIN(X, Y) (((X) < (Y)) ? (X) : (Y)) + typedef struct { PyObject_HEAD @@ -145,8 +147,10 @@ if (result == NULL) return NULL; c->bzs.next_in = data; - /* FIXME This is not 64-bit clean - avail_in is an int. */ - c->bzs.avail_in = len; + /* On a 64-bit system, len might not fit in avail_in (an unsigned int). + Do compression in chunks of no more than UINT_MAX bytes each. */ + c->bzs.avail_in = MIN(len, UINT_MAX); + len -= c->bzs.avail_in; c->bzs.next_out = PyBytes_AS_STRING(result); c->bzs.avail_out = PyBytes_GET_SIZE(result); for (;;) { @@ -161,6 +165,11 @@ if (catch_bz2_error(bzerror)) goto error; + if (c->bzs.avail_in == 0 && len > 0) { + c->bzs.avail_in = MIN(len, UINT_MAX); + len -= c->bzs.avail_in; + } + /* In regular compression mode, stop when input data is exhausted. In flushing mode, stop when all buffered data has been flushed. */ if ((action == BZ_RUN && c->bzs.avail_in == 0) || @@ -354,8 +363,10 @@ if (result == NULL) return result; d->bzs.next_in = data; - /* FIXME This is not 64-bit clean - avail_in is an int. */ - d->bzs.avail_in = len; + /* On a 64-bit system, len might not fit in avail_in (an unsigned int). + Do decompression in chunks of no more than UINT_MAX bytes each. */ + d->bzs.avail_in = MIN(len, UINT_MAX); + len -= d->bzs.avail_in; d->bzs.next_out = PyBytes_AS_STRING(result); d->bzs.avail_out = PyBytes_GET_SIZE(result); for (;;) { @@ -371,17 +382,21 @@ goto error; if (bzerror == BZ_STREAM_END) { d->eof = 1; - if (d->bzs.avail_in > 0) { /* Save leftover input to unused_data */ + len += d->bzs.avail_in; + if (len > 0) { /* Save leftover input to unused_data */ Py_CLEAR(d->unused_data); - d->unused_data = PyBytes_FromStringAndSize(d->bzs.next_in, - d->bzs.avail_in); + d->unused_data = PyBytes_FromStringAndSize(d->bzs.next_in, len); if (d->unused_data == NULL) goto error; } break; } - if (d->bzs.avail_in == 0) - break; + if (d->bzs.avail_in == 0) { + if (len == 0) + break; + d->bzs.avail_in = MIN(len, UINT_MAX); + len -= d->bzs.avail_in; + } if (d->bzs.avail_out == 0) { if (grow_buffer(&result) < 0) goto error; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 12 23:44:44 2011 From: python-checkins at python.org (victor.stinner) Date: Tue, 12 Apr 2011 23:44:44 +0200 Subject: [Python-checkins] cpython: Issue #11186: pydoc ignores a module if its name contains a surrogate character Message-ID: http://hg.python.org/cpython/rev/506cab8fc329 changeset: 69276:506cab8fc329 user: Victor Stinner date: Tue Apr 12 23:41:50 2011 +0200 summary: Issue #11186: pydoc ignores a module if its name contains a surrogate character in the index of modules. files: Lib/pydoc.py | 3 +++ Misc/NEWS | 3 +++ 2 files changed, 6 insertions(+), 0 deletions(-) diff --git a/Lib/pydoc.py b/Lib/pydoc.py --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -952,6 +952,9 @@ modpkgs = [] if shadowed is None: shadowed = {} for importer, name, ispkg in pkgutil.iter_modules([dir]): + if any((0xD800 <= ord(ch) <= 0xDFFF) for ch in name): + # ignore a module if its name contains a surrogate character + continue modpkgs.append((name, '', ispkg, name in shadowed)) shadowed[name] = 1 diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -103,6 +103,9 @@ Library ------- +- Issue #11186: pydoc ignores a module if its name contains a surrogate + character in the index of modules. + - Issue #11815: Use a light-weight SimpleQueue for the result queue in concurrent.futures.ProcessPoolExecutor. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 12 23:59:53 2011 From: python-checkins at python.org (brett.cannon) Date: Tue, 12 Apr 2011 23:59:53 +0200 Subject: [Python-checkins] peps: Drop the propcheck target as that was a svn-specific thing. Message-ID: http://hg.python.org/peps/rev/7415e03f11cf changeset: 3864:7415e03f11cf user: Brett Cannon date: Tue Apr 12 14:30:10 2011 -0700 summary: Drop the propcheck target as that was a svn-specific thing. files: Makefile | 2 -- 1 files changed, 0 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile --- a/Makefile +++ b/Makefile @@ -31,5 +31,3 @@ update: hg pull --update http://hg.python.org/peps -propcheck: - $(PYTHON) propcheck.py -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Tue Apr 12 23:59:53 2011 From: python-checkins at python.org (brett.cannon) Date: Tue, 12 Apr 2011 23:59:53 +0200 Subject: [Python-checkins] peps: Update PEP 399 to include comments from python-dev. Message-ID: http://hg.python.org/peps/rev/24d68b6329e9 changeset: 3865:24d68b6329e9 user: Brett Cannon date: Tue Apr 12 14:59:45 2011 -0700 summary: Update PEP 399 to include comments from python-dev. files: pep-0399.txt | 94 +++++++++++++++++++++++++-------------- 1 files changed, 59 insertions(+), 35 deletions(-) diff --git a/pep-0399.txt b/pep-0399.txt --- a/pep-0399.txt +++ b/pep-0399.txt @@ -8,19 +8,19 @@ Content-Type: text/x-rst Created: 04-Apr-2011 Python-Version: 3.3 -Post-History: +Post-History: 04-Apr-2011, 12-Apr-2011 Abstract ======== The Python standard library under CPython contains various instances of modules implemented in both pure Python and C (either entirely or -partially). This PEP requires that in these instances that both the -Python and C code *must* be semantically identical (except in cases -where implementation details of a VM prevents it entirely). It is also -required that new C-based modules lacking a pure Python equivalent -implementation get special permissions to be added to the standard -library. +partially). This PEP requires that in these instances that the +C code *must* pass the test suite used for the pure Python code +so as to act as much as a drop-in replacement as possible +(C- and VM-specific tests are exempt). It is also required that new +C-based modules lacking a pure Python equivalent implementation get +special permissions to be added to the standard library. Rationale @@ -48,18 +48,22 @@ mandating that all new modules added to Python's standard library *must* have a pure Python implementation _unless_ special dispensation is given. This makes sure that a module in the stdlib is available to -all VMs and not just to CPython. +all VMs and not just to CPython (pre-existing modules that do not meet +this requirement are exempt, although there is nothing preventing +someone from adding in a pure Python implementation retroactively). Re-implementing parts (or all) of a module in C (in the case of CPython) is still allowed for performance reasons, but any such -accelerated code must semantically match the pure Python equivalent to -prevent divergence. To accomplish this, the pure Python and C code must -be thoroughly tested with the *same* test suite to verify compliance. +accelerated code must pass the same test suite (sans VM- or C-specific +tests) to verify semantics and prevent divergence. To accomplish this, +the test suite for the module must have 100% branch coverage of the +pure Python implementation before the acceleration code may be added. This is to prevent users from accidentally relying on semantics that are specific to the C code and are not reflected in -the pure Python implementation that other VMs rely upon, e.g., in -CPython 3.2.0, ``heapq.heappop()`` raises different exceptions -depending on whether the accelerated C code is used or not:: +the pure Python implementation that other VMs rely upon. For example, +in CPython 3.2.0, ``heapq.heappop()`` does an explicit type +check in its accelerated C code while the Python code uses duck +typing:: from test.support import import_fresh_module @@ -77,13 +81,13 @@ try: c_heapq.heappop(Spam()) except TypeError: - # "heap argument must be a list" + # Explicit type check failure: "heap argument must be a list" pass try: py_heapq.heappop(Spam()) except AttributeError: - # "'Foo' object has no attribute 'pop'" + # Duck typing failure: "'Foo' object has no attribute 'pop'" pass This kind of divergence is a problem for users as they unwittingly @@ -99,11 +103,11 @@ Starting in Python 3.3, any modules added to the standard library must have a pure Python implementation. This rule can only be ignored if the Python development team grants a special exemption for the module. -Typically the exemption would be granted only when a module wraps a +Typically the exemption will be granted only when a module wraps a specific C-based library (e.g., sqlite3_). In granting an exemption it -will be recognized that the module will most likely be considered -exclusive to CPython and not part of Python's standard library that -other VMs are expected to support. Usage of ``ctypes`` to provide an +will be recognized that the module will be considered exclusive to +CPython and not part of Python's standard library that other VMs are +expected to support. Usage of ``ctypes`` to provide an API for a C library will continue to be frowned upon as ``ctypes`` lacks compiler guarantees that C code typically relies upon to prevent certain errors from occurring (e.g., API changes). @@ -126,18 +130,34 @@ implementation of the ``csv`` module and maintaining it) then such code will be accepted. -Any accelerated code must be semantically identical to the pure Python -implementation. The only time any semantics are allowed to be -different are when technical details of the VM providing the -accelerated code prevent matching semantics from being possible, e.g., -a class being a ``type`` when implemented in C. The semantics -equivalence requirement also dictates that no public API be provided -in accelerated code that does not exist in the pure Python code. -Without this requirement people could accidentally come to rely on a -detail in the accelerated code which is not made available to other VMs -that use the pure Python implementation. To help verify that the -contract of semantic equivalence is being met, a module must be tested -both with and without its accelerated code as thoroughly as possible. +This requirement does not apply to modules already existing as only C +code in the standard library. It is acceptable to retroactively add a +pure Python implementation of a module implemented entirely in C, but +in those instances the C version is considered the reference +implementation in terms of expected semantics. + +Any new accelerated code must act as a drop-in replacement as close +to the pure Python implementation as reasonable. Technical details of +the VM providing the accelerated code are allowed to differ as +necessary, e.g., a class being a ``type`` when implemented in C. To +verify that the Python and equivalent C code operate as similarly as +possible, both code bases must be tested using the same tests which +apply to the pure Python code (tests specific to the C code or any VM +do not follow under this requirement). To make sure that the test +suite is thorough enough to cover all relevant semantics, the tests +must have 100% branch coverage for the Python code being replaced by +C code. This will make sure that the new acceleration code will +operate as much like a drop-in replacement for the Python code is as +possible. + +Acting as a drop-in replacement also dictates that no public API be +provided in accelerated code that does not exist in the pure Python +code. Without this requirement people could accidentally come to rely +on a detail in the accelerated code which is not made available to +other VMs that use the pure Python implementation. To help verify +that the contract of semantic equivalence is being met, a module must +be tested both with and without its accelerated code as thoroughly as +possible. As an example, to write tests which exercise both the pure Python and C accelerated versions of a module, a basic idiom can be followed:: @@ -189,9 +209,13 @@ if __name__ == '__main__': test_main() -Thoroughness of the test can be verified using coverage measurements -with branching coverage on the pure Python code to verify that all -possible scenarios are tested using (or not using) accelerator code. + +If this test were to provide 100% branch coverage for +``heapq.heappop()`` in the pure Python implementation then the +accelerated C code would be allowed to be added to CPython's standard +library. If it did not, then the test suite would need to be updated +until 100% branch coverage was provided before the accelerated C code +could be added. Copyright -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Wed Apr 13 00:04:01 2011 From: python-checkins at python.org (brett.cannon) Date: Wed, 13 Apr 2011 00:04:01 +0200 Subject: [Python-checkins] peps: Mention that tests that cover C-specific issues are a good thing. Message-ID: http://hg.python.org/peps/rev/cb4815d2aba0 changeset: 3866:cb4815d2aba0 user: Brett Cannon date: Tue Apr 12 15:03:54 2011 -0700 summary: Mention that tests that cover C-specific issues are a good thing. files: pep-0399.txt | 6 +++++- 1 files changed, 5 insertions(+), 1 deletions(-) diff --git a/pep-0399.txt b/pep-0399.txt --- a/pep-0399.txt +++ b/pep-0399.txt @@ -148,7 +148,11 @@ must have 100% branch coverage for the Python code being replaced by C code. This will make sure that the new acceleration code will operate as much like a drop-in replacement for the Python code is as -possible. +possible. Testing should still be done for issues that come up when +working with C code even if it is not explicitly required to meet the +coverage requirement, e.g., Tests should be aware that C code typically +has special paths for things such as built-in types, subclasses of +built-in types, etc. Acting as a drop-in replacement also dictates that no public API be provided in accelerated code that does not exist in the pure Python -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Wed Apr 13 00:26:10 2011 From: python-checkins at python.org (raymond.hettinger) Date: Wed, 13 Apr 2011 00:26:10 +0200 Subject: [Python-checkins] cpython (3.1): Issue 11747: Fix output format for context diffs. Message-ID: http://hg.python.org/cpython/rev/707078ca0a77 changeset: 69277:707078ca0a77 branch: 3.1 parent: 69272:f9bd0add9732 user: Raymond Hettinger date: Tue Apr 12 15:14:12 2011 -0700 summary: Issue 11747: Fix output format for context diffs. files: Lib/difflib.py | 108 ++++++++++++++++++--------- Lib/test/test_difflib.py | 65 ++++++++++++++++- 2 files changed, 136 insertions(+), 37 deletions(-) diff --git a/Lib/difflib.py b/Lib/difflib.py --- a/Lib/difflib.py +++ b/Lib/difflib.py @@ -1140,6 +1140,21 @@ return ch in ws +######################################################################## +### Unified Diff +######################################################################## + +def _format_range_unified(start, stop): + 'Convert range to the "ed" format' + # Per the diff spec at http://www.unix.org/single_unix_specification/ + beginning = start + 1 # lines start numbering with one + length = stop - start + if length == 1: + return '{}'.format(beginning) + if not length: + beginning -= 1 # empty ranges begin at line just before the range + return '{},{}'.format(beginning, length) + def unified_diff(a, b, fromfile='', tofile='', fromfiledate='', tofiledate='', n=3, lineterm='\n'): r""" @@ -1160,18 +1175,18 @@ The unidiff format normally has a header for filenames and modification times. Any or all of these may be specified using strings for - 'fromfile', 'tofile', 'fromfiledate', and 'tofiledate'. The modification - times are normally expressed in the format returned by time.ctime(). + 'fromfile', 'tofile', 'fromfiledate', and 'tofiledate'. + The modification times are normally expressed in the ISO 8601 format. Example: >>> for line in unified_diff('one two three four'.split(), ... 'zero one tree four'.split(), 'Original', 'Current', - ... 'Sat Jan 26 23:30:50 1991', 'Fri Jun 06 10:20:52 2003', + ... '2005-01-26 23:30:50', '2010-04-02 10:20:52', ... lineterm=''): - ... print(line) - --- Original Sat Jan 26 23:30:50 1991 - +++ Current Fri Jun 06 10:20:52 2003 + ... print(line) # doctest: +NORMALIZE_WHITESPACE + --- Original 2005-01-26 23:30:50 + +++ Current 2010-04-02 10:20:52 @@ -1,4 +1,4 @@ +zero one @@ -1184,23 +1199,45 @@ started = False for group in SequenceMatcher(None,a,b).get_grouped_opcodes(n): if not started: - yield '--- %s %s%s' % (fromfile, fromfiledate, lineterm) - yield '+++ %s %s%s' % (tofile, tofiledate, lineterm) started = True - i1, i2, j1, j2 = group[0][1], group[-1][2], group[0][3], group[-1][4] - yield "@@ -%d,%d +%d,%d @@%s" % (i1+1, i2-i1, j1+1, j2-j1, lineterm) + fromdate = '\t{}'.format(fromfiledate) if fromfiledate else '' + todate = '\t{}'.format(tofiledate) if tofiledate else '' + yield '--- {}{}{}'.format(fromfile, fromdate, lineterm) + yield '+++ {}{}{}'.format(tofile, todate, lineterm) + + first, last = group[0], group[-1] + file1_range = _format_range_unified(first[1], last[2]) + file2_range = _format_range_unified(first[3], last[4]) + yield '@@ -{} +{} @@{}'.format(file1_range, file2_range, lineterm) + for tag, i1, i2, j1, j2 in group: if tag == 'equal': for line in a[i1:i2]: yield ' ' + line continue - if tag == 'replace' or tag == 'delete': + if tag in {'replace', 'delete'}: for line in a[i1:i2]: yield '-' + line - if tag == 'replace' or tag == 'insert': + if tag in {'replace', 'insert'}: for line in b[j1:j2]: yield '+' + line + +######################################################################## +### Context Diff +######################################################################## + +def _format_range_context(start, stop): + 'Convert range to the "ed" format' + # Per the diff spec at http://www.unix.org/single_unix_specification/ + beginning = start + 1 # lines start numbering with one + length = stop - start + if not length: + beginning -= 1 # empty ranges begin at line just before the range + if length <= 1: + return '{}'.format(beginning) + return '{},{}'.format(beginning, beginning + length - 1) + # See http://www.unix.org/single_unix_specification/ def context_diff(a, b, fromfile='', tofile='', fromfiledate='', tofiledate='', n=3, lineterm='\n'): @@ -1223,17 +1260,16 @@ The context diff format normally has a header for filenames and modification times. Any or all of these may be specified using strings for 'fromfile', 'tofile', 'fromfiledate', and 'tofiledate'. - The modification times are normally expressed in the format returned - by time.ctime(). If not specified, the strings default to blanks. + The modification times are normally expressed in the ISO 8601 format. + If not specified, the strings default to blanks. Example: >>> print(''.join(context_diff('one\ntwo\nthree\nfour\n'.splitlines(1), - ... 'zero\none\ntree\nfour\n'.splitlines(1), 'Original', 'Current', - ... 'Sat Jan 26 23:30:50 1991', 'Fri Jun 06 10:22:46 2003')), + ... 'zero\none\ntree\nfour\n'.splitlines(1), 'Original', 'Current')), ... end="") - *** Original Sat Jan 26 23:30:50 1991 - --- Current Fri Jun 06 10:22:46 2003 + *** Original + --- Current *************** *** 1,4 **** one @@ -1247,36 +1283,36 @@ four """ + prefix = dict(insert='+ ', delete='- ', replace='! ', equal=' ') started = False - prefixmap = {'insert':'+ ', 'delete':'- ', 'replace':'! ', 'equal':' '} for group in SequenceMatcher(None,a,b).get_grouped_opcodes(n): if not started: - yield '*** %s %s%s' % (fromfile, fromfiledate, lineterm) - yield '--- %s %s%s' % (tofile, tofiledate, lineterm) started = True + fromdate = '\t{}'.format(fromfiledate) if fromfiledate else '' + todate = '\t{}'.format(tofiledate) if tofiledate else '' + yield '*** {}{}{}'.format(fromfile, fromdate, lineterm) + yield '--- {}{}{}'.format(tofile, todate, lineterm) - yield '***************%s' % (lineterm,) - if group[-1][2] - group[0][1] >= 2: - yield '*** %d,%d ****%s' % (group[0][1]+1, group[-1][2], lineterm) - else: - yield '*** %d ****%s' % (group[-1][2], lineterm) - visiblechanges = [e for e in group if e[0] in ('replace', 'delete')] - if visiblechanges: + first, last = group[0], group[-1] + yield '***************' + lineterm + + file1_range = _format_range_context(first[1], last[2]) + yield '*** {} ****{}'.format(file1_range, lineterm) + + if any(tag in {'replace', 'delete'} for tag, _, _, _, _ in group): for tag, i1, i2, _, _ in group: if tag != 'insert': for line in a[i1:i2]: - yield prefixmap[tag] + line + yield prefix[tag] + line - if group[-1][4] - group[0][3] >= 2: - yield '--- %d,%d ----%s' % (group[0][3]+1, group[-1][4], lineterm) - else: - yield '--- %d ----%s' % (group[-1][4], lineterm) - visiblechanges = [e for e in group if e[0] in ('replace', 'insert')] - if visiblechanges: + file2_range = _format_range_context(first[3], last[4]) + yield '--- {} ----{}'.format(file2_range, lineterm) + + if any(tag in {'replace', 'insert'} for tag, _, _, _, _ in group): for tag, _, _, j1, j2 in group: if tag != 'delete': for line in b[j1:j2]: - yield prefixmap[tag] + line + yield prefix[tag] + line def ndiff(a, b, linejunk=None, charjunk=IS_CHARACTER_JUNK): r""" diff --git a/Lib/test/test_difflib.py b/Lib/test/test_difflib.py --- a/Lib/test/test_difflib.py +++ b/Lib/test/test_difflib.py @@ -159,10 +159,73 @@ difflib.SequenceMatcher(None, old, new).get_opcodes() +class TestOutputFormat(unittest.TestCase): + def test_tab_delimiter(self): + args = ['one', 'two', 'Original', 'Current', + '2005-01-26 23:30:50', '2010-04-02 10:20:52'] + ud = difflib.unified_diff(*args, lineterm='') + self.assertEqual(list(ud)[0:2], [ + "--- Original\t2005-01-26 23:30:50", + "+++ Current\t2010-04-02 10:20:52"]) + cd = difflib.context_diff(*args, lineterm='') + self.assertEqual(list(cd)[0:2], [ + "*** Original\t2005-01-26 23:30:50", + "--- Current\t2010-04-02 10:20:52"]) + + def test_no_trailing_tab_on_empty_filedate(self): + args = ['one', 'two', 'Original', 'Current'] + ud = difflib.unified_diff(*args, lineterm='') + self.assertEqual(list(ud)[0:2], ["--- Original", "+++ Current"]) + + cd = difflib.context_diff(*args, lineterm='') + self.assertEqual(list(cd)[0:2], ["*** Original", "--- Current"]) + + def test_range_format_unified(self): + # Per the diff spec at http://www.unix.org/single_unix_specification/ + spec = '''\ + Each field shall be of the form: + %1d", if the range contains exactly one line, + and: + "%1d,%1d", , otherwise. + If a range is empty, its beginning line number shall be the number of + the line just before the range, or 0 if the empty range starts the file. + ''' + fmt = difflib._format_range_unified + self.assertEqual(fmt(3,3), '3,0') + self.assertEqual(fmt(3,4), '4') + self.assertEqual(fmt(3,5), '4,2') + self.assertEqual(fmt(3,6), '4,3') + self.assertEqual(fmt(0,0), '0,0') + + def test_range_format_context(self): + # Per the diff spec at http://www.unix.org/single_unix_specification/ + spec = '''\ + The range of lines in file1 shall be written in the following format + if the range contains two or more lines: + "*** %d,%d ****\n", , + and the following format otherwise: + "*** %d ****\n", + The ending line number of an empty range shall be the number of the preceding line, + or 0 if the range is at the start of the file. + + Next, the range of lines in file2 shall be written in the following format + if the range contains two or more lines: + "--- %d,%d ----\n", , + and the following format otherwise: + "--- %d ----\n", + ''' + fmt = difflib._format_range_context + self.assertEqual(fmt(3,3), '3') + self.assertEqual(fmt(3,4), '4') + self.assertEqual(fmt(3,5), '4,5') + self.assertEqual(fmt(3,6), '4,6') + self.assertEqual(fmt(0,0), '0') + + def test_main(): difflib.HtmlDiff._default_prefix = 0 Doctests = doctest.DocTestSuite(difflib) - run_unittest(TestSFpatches, TestSFbugs, Doctests) + run_unittest(TestSFpatches, TestSFbugs, Doctests, TestOutputFormat) if __name__ == '__main__': test_main() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 13 00:26:13 2011 From: python-checkins at python.org (raymond.hettinger) Date: Wed, 13 Apr 2011 00:26:13 +0200 Subject: [Python-checkins] cpython (3.2): Issue 11747: Fix output format for context diffs. Message-ID: http://hg.python.org/cpython/rev/e3387295a24f changeset: 69278:e3387295a24f branch: 3.2 parent: 69273:4254085bae84 user: Raymond Hettinger date: Tue Apr 12 15:19:33 2011 -0700 summary: Issue 11747: Fix output format for context diffs. files: Lib/difflib.py | 30 +++++++++++++++++++++++---- Lib/test/test_difflib.py | 29 +++++++++++++++++++++++++- 2 files changed, 52 insertions(+), 7 deletions(-) diff --git a/Lib/difflib.py b/Lib/difflib.py --- a/Lib/difflib.py +++ b/Lib/difflib.py @@ -1144,7 +1144,11 @@ return ch in ws -def _format_range(start, stop): +######################################################################## +### Unified Diff +######################################################################## + +def _format_range_unified(start, stop): 'Convert range to the "ed" format' # Per the diff spec at http://www.unix.org/single_unix_specification/ beginning = start + 1 # lines start numbering with one @@ -1206,8 +1210,8 @@ yield '+++ {}{}{}'.format(tofile, todate, lineterm) first, last = group[0], group[-1] - file1_range = _format_range(first[1], last[2]) - file2_range = _format_range(first[3], last[4]) + file1_range = _format_range_unified(first[1], last[2]) + file2_range = _format_range_unified(first[3], last[4]) yield '@@ -{} +{} @@{}'.format(file1_range, file2_range, lineterm) for tag, i1, i2, j1, j2 in group: @@ -1222,6 +1226,22 @@ for line in b[j1:j2]: yield '+' + line + +######################################################################## +### Context Diff +######################################################################## + +def _format_range_context(start, stop): + 'Convert range to the "ed" format' + # Per the diff spec at http://www.unix.org/single_unix_specification/ + beginning = start + 1 # lines start numbering with one + length = stop - start + if not length: + beginning -= 1 # empty ranges begin at line just before the range + if length <= 1: + return '{}'.format(beginning) + return '{},{}'.format(beginning, beginning + length - 1) + # See http://www.unix.org/single_unix_specification/ def context_diff(a, b, fromfile='', tofile='', fromfiledate='', tofiledate='', n=3, lineterm='\n'): @@ -1280,7 +1300,7 @@ first, last = group[0], group[-1] yield '***************' + lineterm - file1_range = _format_range(first[1], last[2]) + file1_range = _format_range_context(first[1], last[2]) yield '*** {} ****{}'.format(file1_range, lineterm) if any(tag in {'replace', 'delete'} for tag, _, _, _, _ in group): @@ -1289,7 +1309,7 @@ for line in a[i1:i2]: yield prefix[tag] + line - file2_range = _format_range(first[3], last[4]) + file2_range = _format_range_context(first[3], last[4]) yield '--- {} ----{}'.format(file2_range, lineterm) if any(tag in {'replace', 'insert'} for tag, _, _, _, _ in group): diff --git a/Lib/test/test_difflib.py b/Lib/test/test_difflib.py --- a/Lib/test/test_difflib.py +++ b/Lib/test/test_difflib.py @@ -236,7 +236,7 @@ cd = difflib.context_diff(*args, lineterm='') self.assertEqual(list(cd)[0:2], ["*** Original", "--- Current"]) - def test_range_format(self): + def test_range_format_unified(self): # Per the diff spec at http://www.unix.org/single_unix_specification/ spec = '''\ Each field shall be of the form: @@ -246,13 +246,38 @@ If a range is empty, its beginning line number shall be the number of the line just before the range, or 0 if the empty range starts the file. ''' - fmt = difflib._format_range + fmt = difflib._format_range_unified self.assertEqual(fmt(3,3), '3,0') self.assertEqual(fmt(3,4), '4') self.assertEqual(fmt(3,5), '4,2') self.assertEqual(fmt(3,6), '4,3') self.assertEqual(fmt(0,0), '0,0') + def test_range_format_context(self): + # Per the diff spec at http://www.unix.org/single_unix_specification/ + spec = '''\ + The range of lines in file1 shall be written in the following format + if the range contains two or more lines: + "*** %d,%d ****\n", , + and the following format otherwise: + "*** %d ****\n", + The ending line number of an empty range shall be the number of the preceding line, + or 0 if the range is at the start of the file. + + Next, the range of lines in file2 shall be written in the following format + if the range contains two or more lines: + "--- %d,%d ----\n", , + and the following format otherwise: + "--- %d ----\n", + ''' + fmt = difflib._format_range_context + self.assertEqual(fmt(3,3), '3') + self.assertEqual(fmt(3,4), '4') + self.assertEqual(fmt(3,5), '4,5') + self.assertEqual(fmt(3,6), '4,6') + self.assertEqual(fmt(0,0), '0') + + def test_main(): difflib.HtmlDiff._default_prefix = 0 Doctests = doctest.DocTestSuite(difflib) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 13 00:26:18 2011 From: python-checkins at python.org (raymond.hettinger) Date: Wed, 13 Apr 2011 00:26:18 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): Merge Message-ID: http://hg.python.org/cpython/rev/8733fa6d3cfa changeset: 69279:8733fa6d3cfa branch: 3.2 parent: 69278:e3387295a24f parent: 69277:707078ca0a77 user: Raymond Hettinger date: Tue Apr 12 15:24:39 2011 -0700 summary: Merge files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 13 00:26:20 2011 From: python-checkins at python.org (raymond.hettinger) Date: Wed, 13 Apr 2011 00:26:20 +0200 Subject: [Python-checkins] cpython: Issue 11747: Fix output format for context diffs. Message-ID: http://hg.python.org/cpython/rev/fbfd5435889c changeset: 69280:fbfd5435889c parent: 69276:506cab8fc329 user: Raymond Hettinger date: Tue Apr 12 15:25:30 2011 -0700 summary: Issue 11747: Fix output format for context diffs. files: Lib/difflib.py | 30 +++++++++++++++++++++++---- Lib/test/test_difflib.py | 29 +++++++++++++++++++++++++- 2 files changed, 52 insertions(+), 7 deletions(-) diff --git a/Lib/difflib.py b/Lib/difflib.py --- a/Lib/difflib.py +++ b/Lib/difflib.py @@ -1144,7 +1144,11 @@ return ch in ws -def _format_range(start, stop): +######################################################################## +### Unified Diff +######################################################################## + +def _format_range_unified(start, stop): 'Convert range to the "ed" format' # Per the diff spec at http://www.unix.org/single_unix_specification/ beginning = start + 1 # lines start numbering with one @@ -1206,8 +1210,8 @@ yield '+++ {}{}{}'.format(tofile, todate, lineterm) first, last = group[0], group[-1] - file1_range = _format_range(first[1], last[2]) - file2_range = _format_range(first[3], last[4]) + file1_range = _format_range_unified(first[1], last[2]) + file2_range = _format_range_unified(first[3], last[4]) yield '@@ -{} +{} @@{}'.format(file1_range, file2_range, lineterm) for tag, i1, i2, j1, j2 in group: @@ -1222,6 +1226,22 @@ for line in b[j1:j2]: yield '+' + line + +######################################################################## +### Context Diff +######################################################################## + +def _format_range_context(start, stop): + 'Convert range to the "ed" format' + # Per the diff spec at http://www.unix.org/single_unix_specification/ + beginning = start + 1 # lines start numbering with one + length = stop - start + if not length: + beginning -= 1 # empty ranges begin at line just before the range + if length <= 1: + return '{}'.format(beginning) + return '{},{}'.format(beginning, beginning + length - 1) + # See http://www.unix.org/single_unix_specification/ def context_diff(a, b, fromfile='', tofile='', fromfiledate='', tofiledate='', n=3, lineterm='\n'): @@ -1280,7 +1300,7 @@ first, last = group[0], group[-1] yield '***************' + lineterm - file1_range = _format_range(first[1], last[2]) + file1_range = _format_range_context(first[1], last[2]) yield '*** {} ****{}'.format(file1_range, lineterm) if any(tag in {'replace', 'delete'} for tag, _, _, _, _ in group): @@ -1289,7 +1309,7 @@ for line in a[i1:i2]: yield prefix[tag] + line - file2_range = _format_range(first[3], last[4]) + file2_range = _format_range_context(first[3], last[4]) yield '--- {} ----{}'.format(file2_range, lineterm) if any(tag in {'replace', 'insert'} for tag, _, _, _, _ in group): diff --git a/Lib/test/test_difflib.py b/Lib/test/test_difflib.py --- a/Lib/test/test_difflib.py +++ b/Lib/test/test_difflib.py @@ -236,7 +236,7 @@ cd = difflib.context_diff(*args, lineterm='') self.assertEqual(list(cd)[0:2], ["*** Original", "--- Current"]) - def test_range_format(self): + def test_range_format_unified(self): # Per the diff spec at http://www.unix.org/single_unix_specification/ spec = '''\ Each field shall be of the form: @@ -246,13 +246,38 @@ If a range is empty, its beginning line number shall be the number of the line just before the range, or 0 if the empty range starts the file. ''' - fmt = difflib._format_range + fmt = difflib._format_range_unified self.assertEqual(fmt(3,3), '3,0') self.assertEqual(fmt(3,4), '4') self.assertEqual(fmt(3,5), '4,2') self.assertEqual(fmt(3,6), '4,3') self.assertEqual(fmt(0,0), '0,0') + def test_range_format_context(self): + # Per the diff spec at http://www.unix.org/single_unix_specification/ + spec = '''\ + The range of lines in file1 shall be written in the following format + if the range contains two or more lines: + "*** %d,%d ****\n", , + and the following format otherwise: + "*** %d ****\n", + The ending line number of an empty range shall be the number of the preceding line, + or 0 if the range is at the start of the file. + + Next, the range of lines in file2 shall be written in the following format + if the range contains two or more lines: + "--- %d,%d ----\n", , + and the following format otherwise: + "--- %d ----\n", + ''' + fmt = difflib._format_range_context + self.assertEqual(fmt(3,3), '3') + self.assertEqual(fmt(3,4), '4') + self.assertEqual(fmt(3,5), '4,5') + self.assertEqual(fmt(3,6), '4,6') + self.assertEqual(fmt(0,0), '0') + + def test_main(): difflib.HtmlDiff._default_prefix = 0 Doctests = doctest.DocTestSuite(difflib) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 13 00:26:22 2011 From: python-checkins at python.org (raymond.hettinger) Date: Wed, 13 Apr 2011 00:26:22 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge Message-ID: http://hg.python.org/cpython/rev/69573aab3ea7 changeset: 69281:69573aab3ea7 parent: 69280:fbfd5435889c parent: 69279:8733fa6d3cfa user: Raymond Hettinger date: Tue Apr 12 15:25:44 2011 -0700 summary: Merge files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 13 00:48:34 2011 From: python-checkins at python.org (raymond.hettinger) Date: Wed, 13 Apr 2011 00:48:34 +0200 Subject: [Python-checkins] cpython (2.7): Issue 11747: Fix output format for context diffs. Message-ID: http://hg.python.org/cpython/rev/09459397f807 changeset: 69282:09459397f807 branch: 2.7 parent: 69271:f4adc2926bf5 user: Raymond Hettinger date: Tue Apr 12 15:48:25 2011 -0700 summary: Issue 11747: Fix output format for context diffs. files: Lib/difflib.py | 89 +++++++++++++++++++-------- Lib/test/test_difflib.py | 41 ++++++++++++ 2 files changed, 102 insertions(+), 28 deletions(-) diff --git a/Lib/difflib.py b/Lib/difflib.py --- a/Lib/difflib.py +++ b/Lib/difflib.py @@ -1140,6 +1140,21 @@ return ch in ws +######################################################################## +### Unified Diff +######################################################################## + +def _format_range_unified(start, stop): + 'Convert range to the "ed" format' + # Per the diff spec at http://www.unix.org/single_unix_specification/ + beginning = start + 1 # lines start numbering with one + length = stop - start + if length == 1: + return '{}'.format(beginning) + if not length: + beginning -= 1 # empty ranges begin at line just before the range + return '{},{}'.format(beginning, length) + def unified_diff(a, b, fromfile='', tofile='', fromfiledate='', tofiledate='', n=3, lineterm='\n'): r""" @@ -1184,25 +1199,45 @@ started = False for group in SequenceMatcher(None,a,b).get_grouped_opcodes(n): if not started: - fromdate = '\t%s' % fromfiledate if fromfiledate else '' - todate = '\t%s' % tofiledate if tofiledate else '' - yield '--- %s%s%s' % (fromfile, fromdate, lineterm) - yield '+++ %s%s%s' % (tofile, todate, lineterm) started = True - i1, i2, j1, j2 = group[0][1], group[-1][2], group[0][3], group[-1][4] - yield "@@ -%d,%d +%d,%d @@%s" % (i1+1, i2-i1, j1+1, j2-j1, lineterm) + fromdate = '\t{}'.format(fromfiledate) if fromfiledate else '' + todate = '\t{}'.format(tofiledate) if tofiledate else '' + yield '--- {}{}{}'.format(fromfile, fromdate, lineterm) + yield '+++ {}{}{}'.format(tofile, todate, lineterm) + + first, last = group[0], group[-1] + file1_range = _format_range_unified(first[1], last[2]) + file2_range = _format_range_unified(first[3], last[4]) + yield '@@ -{} +{} @@{}'.format(file1_range, file2_range, lineterm) + for tag, i1, i2, j1, j2 in group: if tag == 'equal': for line in a[i1:i2]: yield ' ' + line continue - if tag == 'replace' or tag == 'delete': + if tag in ('replace', 'delete'): for line in a[i1:i2]: yield '-' + line - if tag == 'replace' or tag == 'insert': + if tag in ('replace', 'insert'): for line in b[j1:j2]: yield '+' + line + +######################################################################## +### Context Diff +######################################################################## + +def _format_range_context(start, stop): + 'Convert range to the "ed" format' + # Per the diff spec at http://www.unix.org/single_unix_specification/ + beginning = start + 1 # lines start numbering with one + length = stop - start + if not length: + beginning -= 1 # empty ranges begin at line just before the range + if length <= 1: + return '{}'.format(beginning) + return '{},{}'.format(beginning, beginning + length - 1) + # See http://www.unix.org/single_unix_specification/ def context_diff(a, b, fromfile='', tofile='', fromfiledate='', tofiledate='', n=3, lineterm='\n'): @@ -1247,38 +1282,36 @@ four """ + prefix = dict(insert='+ ', delete='- ', replace='! ', equal=' ') started = False - prefixmap = {'insert':'+ ', 'delete':'- ', 'replace':'! ', 'equal':' '} for group in SequenceMatcher(None,a,b).get_grouped_opcodes(n): if not started: - fromdate = '\t%s' % fromfiledate if fromfiledate else '' - todate = '\t%s' % tofiledate if tofiledate else '' - yield '*** %s%s%s' % (fromfile, fromdate, lineterm) - yield '--- %s%s%s' % (tofile, todate, lineterm) started = True + fromdate = '\t{}'.format(fromfiledate) if fromfiledate else '' + todate = '\t{}'.format(tofiledate) if tofiledate else '' + yield '*** {}{}{}'.format(fromfile, fromdate, lineterm) + yield '--- {}{}{}'.format(tofile, todate, lineterm) - yield '***************%s' % (lineterm,) - if group[-1][2] - group[0][1] >= 2: - yield '*** %d,%d ****%s' % (group[0][1]+1, group[-1][2], lineterm) - else: - yield '*** %d ****%s' % (group[-1][2], lineterm) - visiblechanges = [e for e in group if e[0] in ('replace', 'delete')] - if visiblechanges: + first, last = group[0], group[-1] + yield '***************' + lineterm + + file1_range = _format_range_context(first[1], last[2]) + yield '*** {} ****{}'.format(file1_range, lineterm) + + if any(tag in ('replace', 'delete') for tag, _, _, _, _ in group): for tag, i1, i2, _, _ in group: if tag != 'insert': for line in a[i1:i2]: - yield prefixmap[tag] + line + yield prefix[tag] + line - if group[-1][4] - group[0][3] >= 2: - yield '--- %d,%d ----%s' % (group[0][3]+1, group[-1][4], lineterm) - else: - yield '--- %d ----%s' % (group[-1][4], lineterm) - visiblechanges = [e for e in group if e[0] in ('replace', 'insert')] - if visiblechanges: + file2_range = _format_range_context(first[3], last[4]) + yield '--- {} ----{}'.format(file2_range, lineterm) + + if any(tag in ('replace', 'insert') for tag, _, _, _, _ in group): for tag, _, _, j1, j2 in group: if tag != 'delete': for line in b[j1:j2]: - yield prefixmap[tag] + line + yield prefix[tag] + line def ndiff(a, b, linejunk=None, charjunk=IS_CHARACTER_JUNK): r""" diff --git a/Lib/test/test_difflib.py b/Lib/test/test_difflib.py --- a/Lib/test/test_difflib.py +++ b/Lib/test/test_difflib.py @@ -219,6 +219,47 @@ cd = difflib.context_diff(*args, lineterm='') self.assertEqual(list(cd)[0:2], ["*** Original", "--- Current"]) + def test_range_format_unified(self): + # Per the diff spec at http://www.unix.org/single_unix_specification/ + spec = '''\ + Each field shall be of the form: + %1d", if the range contains exactly one line, + and: + "%1d,%1d", , otherwise. + If a range is empty, its beginning line number shall be the number of + the line just before the range, or 0 if the empty range starts the file. + ''' + fmt = difflib._format_range_unified + self.assertEqual(fmt(3,3), '3,0') + self.assertEqual(fmt(3,4), '4') + self.assertEqual(fmt(3,5), '4,2') + self.assertEqual(fmt(3,6), '4,3') + self.assertEqual(fmt(0,0), '0,0') + + def test_range_format_context(self): + # Per the diff spec at http://www.unix.org/single_unix_specification/ + spec = '''\ + The range of lines in file1 shall be written in the following format + if the range contains two or more lines: + "*** %d,%d ****\n", , + and the following format otherwise: + "*** %d ****\n", + The ending line number of an empty range shall be the number of the preceding line, + or 0 if the range is at the start of the file. + + Next, the range of lines in file2 shall be written in the following format + if the range contains two or more lines: + "--- %d,%d ----\n", , + and the following format otherwise: + "--- %d ----\n", + ''' + fmt = difflib._format_range_context + self.assertEqual(fmt(3,3), '3') + self.assertEqual(fmt(3,4), '4') + self.assertEqual(fmt(3,5), '4,5') + self.assertEqual(fmt(3,6), '4,6') + self.assertEqual(fmt(0,0), '0') + def test_main(): difflib.HtmlDiff._default_prefix = 0 -- Repository URL: http://hg.python.org/cpython From nnorwitz at gmail.com Wed Apr 13 00:54:08 2011 From: nnorwitz at gmail.com (Neal Norwitz) Date: Tue, 12 Apr 2011 18:54:08 -0400 Subject: [Python-checkins] Python Regression Test Failures refleak (1) Message-ID: <20110412225408.GA6481@kbk-i386-bb.dyndns.org> More important issues: ---------------------- test_bz2 leaked [-84, 0, 0] references, sum=-84 Less important issues: ---------------------- From python-checkins at python.org Wed Apr 13 01:07:12 2011 From: python-checkins at python.org (victor.stinner) Date: Wed, 13 Apr 2011 01:07:12 +0200 Subject: [Python-checkins] cpython: Fix #11825: disable regrtest timeout if Python doesn't support threads Message-ID: http://hg.python.org/cpython/rev/64e8d371812c changeset: 69283:64e8d371812c parent: 69281:69573aab3ea7 user: Victor Stinner date: Wed Apr 13 01:06:27 2011 +0200 summary: Fix #11825: disable regrtest timeout if Python doesn't support threads files: Lib/test/regrtest.py | 10 +++++++++- 1 files changed, 9 insertions(+), 1 deletions(-) diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -240,7 +240,7 @@ findleaks=False, use_resources=None, trace=False, coverdir='coverage', runleaks=False, huntrleaks=False, verbose2=False, print_slow=False, random_seed=None, use_mp=None, verbose3=False, forever=False, - header=False, timeout=60*60): + header=False): """Execute a test suite. This also parses command-line options and modifies its behavior @@ -263,6 +263,10 @@ directly to set the values that would normally be set by flags on the command line. """ + if hasattr(faulthandler, 'dump_tracebacks_later'): + timeout = 60*60 + else: + timeout = None replace_stdout() @@ -409,6 +413,10 @@ # join it with the saved CWD so it ends up where the user expects. testdir = os.path.join(support.SAVEDCWD, a) elif o == '--timeout': + if not hasattr(faulthandler, 'dump_tracebacks_later'): + print("--timeout option requires " + "faulthandler.dump_tracebacks_later", file=sys.stderr) + sys.exit(1) timeout = float(a) else: print(("No handler for option {}. Please report this as a bug " -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 13 01:26:12 2011 From: python-checkins at python.org (senthil.kumaran) Date: Wed, 13 Apr 2011 01:26:12 +0200 Subject: [Python-checkins] cpython (3.1): Fix Issue11703 - urllib2.geturl() does not return correct url when the original Message-ID: http://hg.python.org/cpython/rev/3f240a1cd245 changeset: 69284:3f240a1cd245 branch: 3.1 parent: 69277:707078ca0a77 user: Senthil Kumaran date: Wed Apr 13 07:01:19 2011 +0800 summary: Fix Issue11703 - urllib2.geturl() does not return correct url when the original url contains #fragment. Patch Contribution by Santoso Wijaya. files: Lib/test/test_urllib.py | 10 ++++++++++ Lib/test/test_urllib2.py | 15 ++++++++++++++- Lib/test/test_urllib2net.py | 2 +- Lib/urllib/request.py | 9 ++++++--- 4 files changed, 31 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_urllib.py b/Lib/test/test_urllib.py --- a/Lib/test/test_urllib.py +++ b/Lib/test/test_urllib.py @@ -171,6 +171,16 @@ finally: self.unfakehttp() + def test_url_fragment(self): + # Issue #11703: geturl() omits fragments in the original URL. + url = 'http://docs.python.org/library/urllib.html#OK' + self.fakehttp(b'Hello!') + try: + fp = urllib.request.urlopen(url) + self.assertEqual(fp.geturl(), url) + finally: + self.unfakehttp() + def test_read_bogus(self): # urlopen() should raise IOError for many error codes. self.fakehttp(b'''HTTP/1.1 401 Authentication Required diff --git a/Lib/test/test_urllib2.py b/Lib/test/test_urllib2.py --- a/Lib/test/test_urllib2.py +++ b/Lib/test/test_urllib2.py @@ -1024,6 +1024,15 @@ o.open("http://www.example.com/") self.assertFalse(hh.req.has_header("Cookie")) + def test_redirect_fragment(self): + redirected_url = 'http://www.example.com/index.html#OK\r\n\r\n' + hh = MockHTTPHandler(302, 'Location: ' + redirected_url) + hdeh = urllib.request.HTTPDefaultErrorHandler() + hrh = urllib.request.HTTPRedirectHandler() + o = build_test_opener(hh, hdeh, hrh) + fp = o.open('http://www.example.com') + self.assertEqual(fp.geturl(), redirected_url.strip()) + def test_proxy(self): o = OpenerDirector() ph = urllib.request.ProxyHandler(dict(http="proxy.example.com:3128")) @@ -1339,12 +1348,16 @@ req = Request("") self.assertEqual("www.python.org", req.get_host()) - def test_urlwith_fragment(self): + def test_url_fragment(self): req = Request("http://www.python.org/?qs=query#fragment=true") self.assertEqual("/?qs=query", req.get_selector()) req = Request("http://www.python.org/#fun=true") self.assertEqual("/", req.get_selector()) + # Issue 11703: geturl() omits fragment in the original URL. + url = 'http://docs.python.org/library/urllib2.html#OK' + req = Request(url) + self.assertEqual(req.get_full_url(), url) def test_main(verbose=None): from test import test_urllib2 diff --git a/Lib/test/test_urllib2net.py b/Lib/test/test_urllib2net.py --- a/Lib/test/test_urllib2net.py +++ b/Lib/test/test_urllib2net.py @@ -158,7 +158,7 @@ req = urllib.request.Request(urlwith_frag) res = urllib.request.urlopen(req) self.assertEqual(res.geturl(), - "http://docs.python.org/glossary.html") + "http://docs.python.org/glossary.html#glossary") def test_custom_headers(self): url = "http://www.example.com" diff --git a/Lib/urllib/request.py b/Lib/urllib/request.py --- a/Lib/urllib/request.py +++ b/Lib/urllib/request.py @@ -163,7 +163,7 @@ origin_req_host=None, unverifiable=False): # unwrap('') --> 'type://host/path' self.full_url = unwrap(url) - self.full_url, fragment = splittag(self.full_url) + self.full_url, self.fragment = splittag(self.full_url) self.data = data self.headers = {} self._tunnel_host = None @@ -202,7 +202,10 @@ return self.data def get_full_url(self): - return self.full_url + if self.fragment: + return '%s#%s' % (self.full_url, self.fragment) + else: + return self.full_url def get_type(self): return self.type @@ -1106,7 +1109,7 @@ except socket.error as err: raise URLError(err) - r.url = req.full_url + r.url = req.get_full_url() # This line replaces the .msg attribute of the HTTPResponse # with .headers, because urllib clients expect the response to # have the reason in .msg. It would be good to mark this -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 13 01:26:13 2011 From: python-checkins at python.org (senthil.kumaran) Date: Wed, 13 Apr 2011 01:26:13 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): merge from 3.1 Message-ID: http://hg.python.org/cpython/rev/2924d01e31ad changeset: 69285:2924d01e31ad branch: 3.2 parent: 69279:8733fa6d3cfa parent: 69284:3f240a1cd245 user: Senthil Kumaran date: Wed Apr 13 07:22:29 2011 +0800 summary: merge from 3.1 files: Lib/test/test_urllib.py | 10 ++++++++++ Lib/test/test_urllib2.py | 15 ++++++++++++++- Lib/test/test_urllib2net.py | 2 +- Lib/urllib/request.py | 9 ++++++--- 4 files changed, 31 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_urllib.py b/Lib/test/test_urllib.py --- a/Lib/test/test_urllib.py +++ b/Lib/test/test_urllib.py @@ -175,6 +175,16 @@ finally: self.unfakehttp() + def test_url_fragment(self): + # Issue #11703: geturl() omits fragments in the original URL. + url = 'http://docs.python.org/library/urllib.html#OK' + self.fakehttp(b"HTTP/1.1 200 OK\r\n\r\nHello!") + try: + fp = urllib.request.urlopen(url) + self.assertEqual(fp.geturl(), url) + finally: + self.unfakehttp() + def test_willclose(self): self.fakehttp(b"HTTP/1.1 200 OK\r\n\r\nHello!") try: diff --git a/Lib/test/test_urllib2.py b/Lib/test/test_urllib2.py --- a/Lib/test/test_urllib2.py +++ b/Lib/test/test_urllib2.py @@ -1070,6 +1070,15 @@ o.open("http://www.example.com/") self.assertFalse(hh.req.has_header("Cookie")) + def test_redirect_fragment(self): + redirected_url = 'http://www.example.com/index.html#OK\r\n\r\n' + hh = MockHTTPHandler(302, 'Location: ' + redirected_url) + hdeh = urllib.request.HTTPDefaultErrorHandler() + hrh = urllib.request.HTTPRedirectHandler() + o = build_test_opener(hh, hdeh, hrh) + fp = o.open('http://www.example.com') + self.assertEqual(fp.geturl(), redirected_url.strip()) + def test_proxy(self): o = OpenerDirector() ph = urllib.request.ProxyHandler(dict(http="proxy.example.com:3128")) @@ -1385,12 +1394,16 @@ req = Request("") self.assertEqual("www.python.org", req.get_host()) - def test_urlwith_fragment(self): + def test_url_fragment(self): req = Request("http://www.python.org/?qs=query#fragment=true") self.assertEqual("/?qs=query", req.get_selector()) req = Request("http://www.python.org/#fun=true") self.assertEqual("/", req.get_selector()) + # Issue 11703: geturl() omits fragment in the original URL. + url = 'http://docs.python.org/library/urllib2.html#OK' + req = Request(url) + self.assertEqual(req.get_full_url(), url) def test_main(verbose=None): from test import test_urllib2 diff --git a/Lib/test/test_urllib2net.py b/Lib/test/test_urllib2net.py --- a/Lib/test/test_urllib2net.py +++ b/Lib/test/test_urllib2net.py @@ -159,7 +159,7 @@ req = urllib.request.Request(urlwith_frag) res = urllib.request.urlopen(req) self.assertEqual(res.geturl(), - "http://docs.python.org/glossary.html") + "http://docs.python.org/glossary.html#glossary") def test_custom_headers(self): url = "http://www.example.com" diff --git a/Lib/urllib/request.py b/Lib/urllib/request.py --- a/Lib/urllib/request.py +++ b/Lib/urllib/request.py @@ -180,7 +180,7 @@ origin_req_host=None, unverifiable=False): # unwrap('') --> 'type://host/path' self.full_url = unwrap(url) - self.full_url, fragment = splittag(self.full_url) + self.full_url, self.fragment = splittag(self.full_url) self.data = data self.headers = {} self._tunnel_host = None @@ -219,7 +219,10 @@ return self.data def get_full_url(self): - return self.full_url + if self.fragment: + return '%s#%s' % (self.full_url, self.fragment) + else: + return self.full_url def get_type(self): return self.type @@ -1135,7 +1138,7 @@ except socket.error as err: raise URLError(err) - r.url = req.full_url + r.url = req.get_full_url() # This line replaces the .msg attribute of the HTTPResponse # with .headers, because urllib clients expect the response to # have the reason in .msg. It would be good to mark this -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 13 01:26:17 2011 From: python-checkins at python.org (senthil.kumaran) Date: Wed, 13 Apr 2011 01:26:17 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): merge from 3.2 Message-ID: http://hg.python.org/cpython/rev/f54337b9a74a changeset: 69286:f54337b9a74a parent: 69281:69573aab3ea7 parent: 69285:2924d01e31ad user: Senthil Kumaran date: Wed Apr 13 07:24:32 2011 +0800 summary: merge from 3.2 files: Lib/test/test_urllib.py | 10 ++++++++++ Lib/test/test_urllib2.py | 15 ++++++++++++++- Lib/test/test_urllib2net.py | 2 +- Lib/urllib/request.py | 9 ++++++--- 4 files changed, 31 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_urllib.py b/Lib/test/test_urllib.py --- a/Lib/test/test_urllib.py +++ b/Lib/test/test_urllib.py @@ -175,6 +175,16 @@ finally: self.unfakehttp() + def test_url_fragment(self): + # Issue #11703: geturl() omits fragments in the original URL. + url = 'http://docs.python.org/library/urllib.html#OK' + self.fakehttp(b"HTTP/1.1 200 OK\r\n\r\nHello!") + try: + fp = urllib.request.urlopen(url) + self.assertEqual(fp.geturl(), url) + finally: + self.unfakehttp() + def test_willclose(self): self.fakehttp(b"HTTP/1.1 200 OK\r\n\r\nHello!") try: diff --git a/Lib/test/test_urllib2.py b/Lib/test/test_urllib2.py --- a/Lib/test/test_urllib2.py +++ b/Lib/test/test_urllib2.py @@ -1070,6 +1070,15 @@ o.open("http://www.example.com/") self.assertFalse(hh.req.has_header("Cookie")) + def test_redirect_fragment(self): + redirected_url = 'http://www.example.com/index.html#OK\r\n\r\n' + hh = MockHTTPHandler(302, 'Location: ' + redirected_url) + hdeh = urllib.request.HTTPDefaultErrorHandler() + hrh = urllib.request.HTTPRedirectHandler() + o = build_test_opener(hh, hdeh, hrh) + fp = o.open('http://www.example.com') + self.assertEqual(fp.geturl(), redirected_url.strip()) + def test_proxy(self): o = OpenerDirector() ph = urllib.request.ProxyHandler(dict(http="proxy.example.com:3128")) @@ -1385,12 +1394,16 @@ req = Request("") self.assertEqual("www.python.org", req.get_host()) - def test_urlwith_fragment(self): + def test_url_fragment(self): req = Request("http://www.python.org/?qs=query#fragment=true") self.assertEqual("/?qs=query", req.get_selector()) req = Request("http://www.python.org/#fun=true") self.assertEqual("/", req.get_selector()) + # Issue 11703: geturl() omits fragment in the original URL. + url = 'http://docs.python.org/library/urllib2.html#OK' + req = Request(url) + self.assertEqual(req.get_full_url(), url) def test_main(verbose=None): from test import test_urllib2 diff --git a/Lib/test/test_urllib2net.py b/Lib/test/test_urllib2net.py --- a/Lib/test/test_urllib2net.py +++ b/Lib/test/test_urllib2net.py @@ -159,7 +159,7 @@ req = urllib.request.Request(urlwith_frag) res = urllib.request.urlopen(req) self.assertEqual(res.geturl(), - "http://docs.python.org/glossary.html") + "http://docs.python.org/glossary.html#glossary") def test_custom_headers(self): url = "http://www.example.com" diff --git a/Lib/urllib/request.py b/Lib/urllib/request.py --- a/Lib/urllib/request.py +++ b/Lib/urllib/request.py @@ -180,7 +180,7 @@ origin_req_host=None, unverifiable=False): # unwrap('') --> 'type://host/path' self.full_url = unwrap(url) - self.full_url, fragment = splittag(self.full_url) + self.full_url, self.fragment = splittag(self.full_url) self.data = data self.headers = {} self._tunnel_host = None @@ -219,7 +219,10 @@ return self.data def get_full_url(self): - return self.full_url + if self.fragment: + return '%s#%s' % (self.full_url, self.fragment) + else: + return self.full_url def get_type(self): return self.type @@ -1135,7 +1138,7 @@ except socket.error as err: raise URLError(err) - r.url = req.full_url + r.url = req.get_full_url() # This line replaces the .msg attribute of the HTTPResponse # with .headers, because urllib clients expect the response to # have the reason in .msg. It would be good to mark this -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 13 01:26:20 2011 From: python-checkins at python.org (senthil.kumaran) Date: Wed, 13 Apr 2011 01:26:20 +0200 Subject: [Python-checkins] cpython (merge default -> default): merge the change update. Message-ID: http://hg.python.org/cpython/rev/bdca6780be95 changeset: 69287:bdca6780be95 parent: 69286:f54337b9a74a parent: 69283:64e8d371812c user: Senthil Kumaran date: Wed Apr 13 07:25:48 2011 +0800 summary: merge the change update. files: Lib/test/regrtest.py | 10 +++++++++- 1 files changed, 9 insertions(+), 1 deletions(-) diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -240,7 +240,7 @@ findleaks=False, use_resources=None, trace=False, coverdir='coverage', runleaks=False, huntrleaks=False, verbose2=False, print_slow=False, random_seed=None, use_mp=None, verbose3=False, forever=False, - header=False, timeout=60*60): + header=False): """Execute a test suite. This also parses command-line options and modifies its behavior @@ -263,6 +263,10 @@ directly to set the values that would normally be set by flags on the command line. """ + if hasattr(faulthandler, 'dump_tracebacks_later'): + timeout = 60*60 + else: + timeout = None replace_stdout() @@ -409,6 +413,10 @@ # join it with the saved CWD so it ends up where the user expects. testdir = os.path.join(support.SAVEDCWD, a) elif o == '--timeout': + if not hasattr(faulthandler, 'dump_tracebacks_later'): + print("--timeout option requires " + "faulthandler.dump_tracebacks_later", file=sys.stderr) + sys.exit(1) timeout = float(a) else: print(("No handler for option {}. Please report this as a bug " -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 13 01:33:58 2011 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 13 Apr 2011 01:33:58 +0200 Subject: [Python-checkins] cpython (3.1): make assigning to a bytes literal a syntax error (closes #11506) Message-ID: http://hg.python.org/cpython/rev/4d9a8e84279a changeset: 69288:4d9a8e84279a branch: 3.1 parent: 69277:707078ca0a77 user: Benjamin Peterson date: Tue Apr 12 18:33:28 2011 -0500 summary: make assigning to a bytes literal a syntax error (closes #11506) files: Lib/test/test_syntax.py | 4 ++++ Misc/NEWS | 3 +++ Python/ast.c | 1 + 3 files changed, 8 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_syntax.py b/Lib/test/test_syntax.py --- a/Lib/test/test_syntax.py +++ b/Lib/test/test_syntax.py @@ -67,6 +67,10 @@ Traceback (most recent call last): SyntaxError: can't assign to literal +>>> b"" = 1 +Traceback (most recent call last): +SyntaxError: can't assign to literal + >>> `1` = 1 Traceback (most recent call last): SyntaxError: invalid syntax diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -45,6 +45,9 @@ - Issue #5587: add a repr to dict_proxy objects. Patch by David Stanek and Daniel Urban. +- Issue #11506: Trying to assign to a bytes literal should result in a + SyntaxError. + Library ------- diff --git a/Python/ast.c b/Python/ast.c --- a/Python/ast.c +++ b/Python/ast.c @@ -469,6 +469,7 @@ case Set_kind: case Num_kind: case Str_kind: + case Bytes_kind: expr_name = "literal"; break; case Ellipsis_kind: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 13 01:33:59 2011 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 13 Apr 2011 01:33:59 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.1): merge heads Message-ID: http://hg.python.org/cpython/rev/1ea945be3d09 changeset: 69289:1ea945be3d09 branch: 3.1 parent: 69288:4d9a8e84279a parent: 69284:3f240a1cd245 user: Benjamin Peterson date: Tue Apr 12 18:34:06 2011 -0500 summary: merge heads files: Lib/test/test_urllib.py | 10 ++++++++++ Lib/test/test_urllib2.py | 15 ++++++++++++++- Lib/test/test_urllib2net.py | 2 +- Lib/urllib/request.py | 9 ++++++--- 4 files changed, 31 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_urllib.py b/Lib/test/test_urllib.py --- a/Lib/test/test_urllib.py +++ b/Lib/test/test_urllib.py @@ -171,6 +171,16 @@ finally: self.unfakehttp() + def test_url_fragment(self): + # Issue #11703: geturl() omits fragments in the original URL. + url = 'http://docs.python.org/library/urllib.html#OK' + self.fakehttp(b'Hello!') + try: + fp = urllib.request.urlopen(url) + self.assertEqual(fp.geturl(), url) + finally: + self.unfakehttp() + def test_read_bogus(self): # urlopen() should raise IOError for many error codes. self.fakehttp(b'''HTTP/1.1 401 Authentication Required diff --git a/Lib/test/test_urllib2.py b/Lib/test/test_urllib2.py --- a/Lib/test/test_urllib2.py +++ b/Lib/test/test_urllib2.py @@ -1024,6 +1024,15 @@ o.open("http://www.example.com/") self.assertFalse(hh.req.has_header("Cookie")) + def test_redirect_fragment(self): + redirected_url = 'http://www.example.com/index.html#OK\r\n\r\n' + hh = MockHTTPHandler(302, 'Location: ' + redirected_url) + hdeh = urllib.request.HTTPDefaultErrorHandler() + hrh = urllib.request.HTTPRedirectHandler() + o = build_test_opener(hh, hdeh, hrh) + fp = o.open('http://www.example.com') + self.assertEqual(fp.geturl(), redirected_url.strip()) + def test_proxy(self): o = OpenerDirector() ph = urllib.request.ProxyHandler(dict(http="proxy.example.com:3128")) @@ -1339,12 +1348,16 @@ req = Request("") self.assertEqual("www.python.org", req.get_host()) - def test_urlwith_fragment(self): + def test_url_fragment(self): req = Request("http://www.python.org/?qs=query#fragment=true") self.assertEqual("/?qs=query", req.get_selector()) req = Request("http://www.python.org/#fun=true") self.assertEqual("/", req.get_selector()) + # Issue 11703: geturl() omits fragment in the original URL. + url = 'http://docs.python.org/library/urllib2.html#OK' + req = Request(url) + self.assertEqual(req.get_full_url(), url) def test_main(verbose=None): from test import test_urllib2 diff --git a/Lib/test/test_urllib2net.py b/Lib/test/test_urllib2net.py --- a/Lib/test/test_urllib2net.py +++ b/Lib/test/test_urllib2net.py @@ -158,7 +158,7 @@ req = urllib.request.Request(urlwith_frag) res = urllib.request.urlopen(req) self.assertEqual(res.geturl(), - "http://docs.python.org/glossary.html") + "http://docs.python.org/glossary.html#glossary") def test_custom_headers(self): url = "http://www.example.com" diff --git a/Lib/urllib/request.py b/Lib/urllib/request.py --- a/Lib/urllib/request.py +++ b/Lib/urllib/request.py @@ -163,7 +163,7 @@ origin_req_host=None, unverifiable=False): # unwrap('') --> 'type://host/path' self.full_url = unwrap(url) - self.full_url, fragment = splittag(self.full_url) + self.full_url, self.fragment = splittag(self.full_url) self.data = data self.headers = {} self._tunnel_host = None @@ -202,7 +202,10 @@ return self.data def get_full_url(self): - return self.full_url + if self.fragment: + return '%s#%s' % (self.full_url, self.fragment) + else: + return self.full_url def get_type(self): return self.type @@ -1106,7 +1109,7 @@ except socket.error as err: raise URLError(err) - r.url = req.full_url + r.url = req.get_full_url() # This line replaces the .msg attribute of the HTTPResponse # with .headers, because urllib clients expect the response to # have the reason in .msg. It would be good to mark this -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 13 01:34:05 2011 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 13 Apr 2011 01:34:05 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): merge 3.1 Message-ID: http://hg.python.org/cpython/rev/d25c2812b0d8 changeset: 69290:d25c2812b0d8 branch: 3.2 parent: 69285:2924d01e31ad parent: 69289:1ea945be3d09 user: Benjamin Peterson date: Tue Apr 12 18:34:30 2011 -0500 summary: merge 3.1 files: Lib/test/test_syntax.py | 4 ++++ Misc/NEWS | 3 +++ Python/ast.c | 1 + 3 files changed, 8 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_syntax.py b/Lib/test/test_syntax.py --- a/Lib/test/test_syntax.py +++ b/Lib/test/test_syntax.py @@ -67,6 +67,10 @@ Traceback (most recent call last): SyntaxError: can't assign to literal +>>> b"" = 1 +Traceback (most recent call last): +SyntaxError: can't assign to literal + >>> `1` = 1 Traceback (most recent call last): SyntaxError: invalid syntax diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -490,6 +490,9 @@ - Add sys.flags attribute for the new -q command-line option. +- Issue #11506: Trying to assign to a bytes literal should result in a + SyntaxError. + Library ------- diff --git a/Python/ast.c b/Python/ast.c --- a/Python/ast.c +++ b/Python/ast.c @@ -483,6 +483,7 @@ case Set_kind: case Num_kind: case Str_kind: + case Bytes_kind: expr_name = "literal"; break; case Ellipsis_kind: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 13 01:34:06 2011 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 13 Apr 2011 01:34:06 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): merge 3.2 Message-ID: http://hg.python.org/cpython/rev/0e6359968b80 changeset: 69291:0e6359968b80 parent: 69287:bdca6780be95 parent: 69290:d25c2812b0d8 user: Benjamin Peterson date: Tue Apr 12 18:35:21 2011 -0500 summary: merge 3.2 files: Lib/test/test_syntax.py | 4 ++++ Misc/NEWS | 3 +++ Python/ast.c | 1 + 3 files changed, 8 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_syntax.py b/Lib/test/test_syntax.py --- a/Lib/test/test_syntax.py +++ b/Lib/test/test_syntax.py @@ -67,6 +67,10 @@ Traceback (most recent call last): SyntaxError: can't assign to literal +>>> b"" = 1 +Traceback (most recent call last): +SyntaxError: can't assign to literal + >>> `1` = 1 Traceback (most recent call last): SyntaxError: invalid syntax diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -716,6 +716,9 @@ - Add sys.flags attribute for the new -q command-line option. +- Issue #11506: Trying to assign to a bytes literal should result in a + SyntaxError. + Library ------- diff --git a/Python/ast.c b/Python/ast.c --- a/Python/ast.c +++ b/Python/ast.c @@ -483,6 +483,7 @@ case Set_kind: case Num_kind: case Str_kind: + case Bytes_kind: expr_name = "literal"; break; case Ellipsis_kind: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 13 01:36:24 2011 From: python-checkins at python.org (senthil.kumaran) Date: Wed, 13 Apr 2011 01:36:24 +0200 Subject: [Python-checkins] cpython (2.7): Fix Issue11703 - urllib2.get_url does not handle fragment in url properly. Message-ID: http://hg.python.org/cpython/rev/6e73f75ee034 changeset: 69292:6e73f75ee034 branch: 2.7 parent: 69282:09459397f807 user: Senthil Kumaran date: Wed Apr 13 07:31:45 2011 +0800 summary: Fix Issue11703 - urllib2.get_url does not handle fragment in url properly. files: Lib/test/test_urllib.py | 10 ++++++++++ Lib/test/test_urllib2.py | 15 ++++++++++++++- Lib/test/test_urllib2net.py | 2 +- Lib/urllib2.py | 7 +++++-- 4 files changed, 30 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_urllib.py b/Lib/test/test_urllib.py --- a/Lib/test/test_urllib.py +++ b/Lib/test/test_urllib.py @@ -148,6 +148,16 @@ finally: self.unfakehttp() + def test_url_fragment(self): + # Issue #11703: geturl() omits fragments in the original URL. + url = 'http://docs.python.org/library/urllib.html#OK' + self.fakehttp('Hello!') + try: + fp = urllib.urlopen(url) + self.assertEqual(fp.geturl(), url) + finally: + self.unfakehttp() + def test_read_bogus(self): # urlopen() should raise IOError for many error codes. self.fakehttp('''HTTP/1.1 401 Authentication Required diff --git a/Lib/test/test_urllib2.py b/Lib/test/test_urllib2.py --- a/Lib/test/test_urllib2.py +++ b/Lib/test/test_urllib2.py @@ -1007,6 +1007,15 @@ o.open("http://www.example.com/") self.assertTrue(not hh.req.has_header("Cookie")) + def test_redirect_fragment(self): + redirected_url = 'http://www.example.com/index.html#OK\r\n\r\n' + hh = MockHTTPHandler(302, 'Location: ' + redirected_url) + hdeh = urllib2.HTTPDefaultErrorHandler() + hrh = urllib2.HTTPRedirectHandler() + o = build_test_opener(hh, hdeh, hrh) + fp = o.open('http://www.example.com') + self.assertEqual(fp.geturl(), redirected_url.strip()) + def test_proxy(self): o = OpenerDirector() ph = urllib2.ProxyHandler(dict(http="proxy.example.com:3128")) @@ -1292,12 +1301,16 @@ req = Request("") self.assertEqual("www.python.org", req.get_host()) - def test_urlwith_fragment(self): + def test_url_fragment(self): req = Request("http://www.python.org/?qs=query#fragment=true") self.assertEqual("/?qs=query", req.get_selector()) req = Request("http://www.python.org/#fun=true") self.assertEqual("/", req.get_selector()) + # Issue 11703: geturl() omits fragment in the original URL. + url = 'http://docs.python.org/library/urllib2.html#OK' + req = Request(url) + self.assertEqual(req.get_full_url(), url) def test_main(verbose=None): from test import test_urllib2 diff --git a/Lib/test/test_urllib2net.py b/Lib/test/test_urllib2net.py --- a/Lib/test/test_urllib2net.py +++ b/Lib/test/test_urllib2net.py @@ -160,7 +160,7 @@ req = urllib2.Request(urlwith_frag) res = urllib2.urlopen(req) self.assertEqual(res.geturl(), - "http://docs.python.org/glossary.html") + "http://docs.python.org/glossary.html#glossary") def test_fileno(self): req = urllib2.Request("http://www.python.org") diff --git a/Lib/urllib2.py b/Lib/urllib2.py --- a/Lib/urllib2.py +++ b/Lib/urllib2.py @@ -190,7 +190,7 @@ origin_req_host=None, unverifiable=False): # unwrap('') --> 'type://host/path' self.__original = unwrap(url) - self.__original, fragment = splittag(self.__original) + self.__original, self.__fragment = splittag(self.__original) self.type = None # self.__r_type is what's left after doing the splittype self.host = None @@ -236,7 +236,10 @@ return self.data def get_full_url(self): - return self.__original + if self.__fragment: + return '%s#%s' % (self.__original, self.__fragment) + else: + return self.__original def get_type(self): if self.type is None: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 13 03:22:30 2011 From: python-checkins at python.org (r.david.murray) Date: Wed, 13 Apr 2011 03:22:30 +0200 Subject: [Python-checkins] cpython (2.7): #10019: Fix regression relative to 2.6: add newlines if indent=0 Message-ID: http://hg.python.org/cpython/rev/8264f68e8251 changeset: 69293:8264f68e8251 branch: 2.7 user: R David Murray date: Tue Apr 12 21:00:26 2011 -0400 summary: #10019: Fix regression relative to 2.6: add newlines if indent=0 Patch by Amaury Forgeot d'Arc, updated by Sando Tosi. files: Doc/library/json.rst | 6 +++--- Lib/json/encoder.py | 2 +- Lib/json/tests/test_indent.py | 16 ++++++++++++++++ Misc/NEWS | 3 +++ 4 files changed, 23 insertions(+), 4 deletions(-) diff --git a/Doc/library/json.rst b/Doc/library/json.rst --- a/Doc/library/json.rst +++ b/Doc/library/json.rst @@ -139,9 +139,9 @@ using the JavaScript equivalents (``NaN``, ``Infinity``, ``-Infinity``). If *indent* is a non-negative integer, then JSON array elements and object - members will be pretty-printed with that indent level. An indent level of 0 - will only insert newlines. ``None`` (the default) selects the most compact - representation. + members will be pretty-printed with that indent level. An indent level of 0, + or negative, will only insert newlines. ``None`` (the default) selects the + most compact representation. If *separators* is an ``(item_separator, dict_separator)`` tuple, then it will be used instead of the default ``(', ', ': ')`` separators. ``(',', diff --git a/Lib/json/encoder.py b/Lib/json/encoder.py --- a/Lib/json/encoder.py +++ b/Lib/json/encoder.py @@ -251,7 +251,7 @@ if (_one_shot and c_make_encoder is not None - and not self.indent and not self.sort_keys): + and self.indent is None and not self.sort_keys): _iterencode = c_make_encoder( markers, self.default, _encoder, self.indent, self.key_separator, self.item_separator, self.sort_keys, diff --git a/Lib/json/tests/test_indent.py b/Lib/json/tests/test_indent.py --- a/Lib/json/tests/test_indent.py +++ b/Lib/json/tests/test_indent.py @@ -2,6 +2,7 @@ import json import textwrap +from StringIO import StringIO class TestIndent(TestCase): def test_indent(self): @@ -39,3 +40,18 @@ self.assertEqual(h1, h) self.assertEqual(h2, h) self.assertEqual(d2, expect) + + def test_indent0(self): + h = {3: 1} + def check(indent, expected): + d1 = json.dumps(h, indent=indent) + self.assertEqual(d1, expected) + + sio = StringIO() + json.dump(h, sio, indent=indent) + self.assertEqual(sio.getvalue(), expected) + + # indent=0 should emit newlines + check(0, '{\n"3": 1\n}') + # indent=None is more compact + check(None, '{"3": 1}') diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -51,6 +51,9 @@ Library ------- +- Issue #10019: Fixed regression in json module where an indent of 0 stopped + adding newlines and acted instead like 'None'. + - Issue #5162: Treat services like frozen executables to allow child spawning from multiprocessing.forking on Windows. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 13 03:22:31 2011 From: python-checkins at python.org (r.david.murray) Date: Wed, 13 Apr 2011 03:22:31 +0200 Subject: [Python-checkins] cpython (3.1): #10019: Fix regression relative to 2.6: add newlines if indent=0 Message-ID: http://hg.python.org/cpython/rev/4a1048257995 changeset: 69294:4a1048257995 branch: 3.1 parent: 69289:1ea945be3d09 user: R David Murray date: Tue Apr 12 21:02:45 2011 -0400 summary: #10019: Fix regression relative to 2.6: add newlines if indent=0 Patch by Amaury Forgeot d'Arc, updated by Sando Tosi. files: Doc/library/json.rst | 6 +++--- Lib/json/encoder.py | 2 +- Lib/json/tests/test_indent.py | 16 ++++++++++++++++ Misc/NEWS | 3 +++ 4 files changed, 23 insertions(+), 4 deletions(-) diff --git a/Doc/library/json.rst b/Doc/library/json.rst --- a/Doc/library/json.rst +++ b/Doc/library/json.rst @@ -135,9 +135,9 @@ using the JavaScript equivalents (``NaN``, ``Infinity``, ``-Infinity``). If *indent* is a non-negative integer, then JSON array elements and object - members will be pretty-printed with that indent level. An indent level of 0 - will only insert newlines. ``None`` (the default) selects the most compact - representation. + members will be pretty-printed with that indent level. An indent level of 0, + or negative, will only insert newlines. ``None`` (the default) selects the + most compact representation. If *separators* is an ``(item_separator, dict_separator)`` tuple, then it will be used instead of the default ``(', ', ': ')`` separators. ``(',', diff --git a/Lib/json/encoder.py b/Lib/json/encoder.py --- a/Lib/json/encoder.py +++ b/Lib/json/encoder.py @@ -233,7 +233,7 @@ if (_one_shot and c_make_encoder is not None - and not self.indent): + and self.indent is None): _iterencode = c_make_encoder( markers, self.default, _encoder, self.indent, self.key_separator, self.item_separator, self.sort_keys, diff --git a/Lib/json/tests/test_indent.py b/Lib/json/tests/test_indent.py --- a/Lib/json/tests/test_indent.py +++ b/Lib/json/tests/test_indent.py @@ -2,6 +2,7 @@ import json import textwrap +from io import StringIO class TestIndent(TestCase): def test_indent(self): @@ -39,3 +40,18 @@ self.assertEqual(h1, h) self.assertEqual(h2, h) self.assertEqual(d2, expect) + + def test_indent0(self): + h = {3: 1} + def check(indent, expected): + d1 = json.dumps(h, indent=indent) + self.assertEqual(d1, expected) + + sio = StringIO() + json.dump(h, sio, indent=indent) + self.assertEqual(sio.getvalue(), expected) + + # indent=0 should emit newlines + check(0, '{\n"3": 1\n}') + # indent=None is more compact + check(None, '{"3": 1}') diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -51,6 +51,9 @@ Library ------- +- Issue #10019: Fixed regression in json module where an indent of 0 stopped + adding newlines and acted instead like 'None'. + - Issue #5162: Treat services like frozen executables to allow child spawning from multiprocessing.forking on Windows. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 13 03:22:33 2011 From: python-checkins at python.org (r.david.murray) Date: Wed, 13 Apr 2011 03:22:33 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): Merge #10019: Fix regression relative to 2.6: add newlines if indent=0 Message-ID: http://hg.python.org/cpython/rev/fe8bbaff5a27 changeset: 69295:fe8bbaff5a27 branch: 3.2 parent: 69290:d25c2812b0d8 parent: 69294:4a1048257995 user: R David Murray date: Tue Apr 12 21:09:18 2011 -0400 summary: Merge #10019: Fix regression relative to 2.6: add newlines if indent=0 Patch by Amaury Forgeot d'Arc, updated by Sando Tosi. files: Doc/library/json.rst | 8 ++++---- Lib/json/encoder.py | 2 +- Lib/test/json_tests/test_indent.py | 16 ++++++++++++++++ Misc/NEWS | 3 +++ 4 files changed, 24 insertions(+), 5 deletions(-) diff --git a/Doc/library/json.rst b/Doc/library/json.rst --- a/Doc/library/json.rst +++ b/Doc/library/json.rst @@ -136,10 +136,10 @@ If *indent* is a non-negative integer or string, then JSON array elements and object members will be pretty-printed with that indent level. An indent level - of 0 or ``""`` will only insert newlines. ``None`` (the default) selects the - most compact representation. Using an integer indent indents that many spaces - per level. If *indent* is a string (such at '\t'), that string is used to indent - each level. + of 0, negative, or ``""`` will only insert newlines. ``None`` (the default) + selects the most compact representation. Using a positive integer indent + indents that many spaces per level. If *indent* is a string (such at '\t'), + that string is used to indent each level. If *separators* is an ``(item_separator, dict_separator)`` tuple, then it will be used instead of the default ``(', ', ': ')`` separators. ``(',', diff --git a/Lib/json/encoder.py b/Lib/json/encoder.py --- a/Lib/json/encoder.py +++ b/Lib/json/encoder.py @@ -233,7 +233,7 @@ if (_one_shot and c_make_encoder is not None - and not self.indent): + and self.indent is None): _iterencode = c_make_encoder( markers, self.default, _encoder, self.indent, self.key_separator, self.item_separator, self.sort_keys, diff --git a/Lib/test/json_tests/test_indent.py b/Lib/test/json_tests/test_indent.py --- a/Lib/test/json_tests/test_indent.py +++ b/Lib/test/json_tests/test_indent.py @@ -2,6 +2,7 @@ import json import textwrap +from io import StringIO class TestIndent(TestCase): def test_indent(self): @@ -43,3 +44,18 @@ self.assertEqual(h3, h) self.assertEqual(d2, expect.expandtabs(2)) self.assertEqual(d3, expect) + + def test_indent0(self): + h = {3: 1} + def check(indent, expected): + d1 = json.dumps(h, indent=indent) + self.assertEqual(d1, expected) + + sio = StringIO() + json.dump(h, sio, indent=indent) + self.assertEqual(sio.getvalue(), expected) + + # indent=0 should emit newlines + check(0, '{\n"3": 1\n}') + # indent=None is more compact + check(None, '{"3": 1}') diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -53,6 +53,9 @@ Library ------- +- Issue #10019: Fixed regression in json module where an indent of 0 stopped + adding newlines and acted instead like 'None'. + - Issue #5162: Treat services like frozen executables to allow child spawning from multiprocessing.forking on Windows. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 13 03:22:34 2011 From: python-checkins at python.org (r.david.murray) Date: Wed, 13 Apr 2011 03:22:34 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge #10019: Fix regression relative to 2.6: add newlines if indent=0 Message-ID: http://hg.python.org/cpython/rev/2d0d0850335e changeset: 69296:2d0d0850335e parent: 69291:0e6359968b80 parent: 69295:fe8bbaff5a27 user: R David Murray date: Tue Apr 12 21:19:20 2011 -0400 summary: Merge #10019: Fix regression relative to 2.6: add newlines if indent=0 Patch by Amaury Forgeot d'Arc, updated by Sando Tosi. files: Doc/library/json.rst | 8 ++++---- Lib/json/encoder.py | 2 +- Lib/test/json_tests/test_indent.py | 16 ++++++++++++++++ Misc/NEWS | 3 +++ 4 files changed, 24 insertions(+), 5 deletions(-) diff --git a/Doc/library/json.rst b/Doc/library/json.rst --- a/Doc/library/json.rst +++ b/Doc/library/json.rst @@ -136,10 +136,10 @@ If *indent* is a non-negative integer or string, then JSON array elements and object members will be pretty-printed with that indent level. An indent level - of 0 or ``""`` will only insert newlines. ``None`` (the default) selects the - most compact representation. Using an integer indent indents that many spaces - per level. If *indent* is a string (such at '\t'), that string is used to indent - each level. + of 0, negative, or ``""`` will only insert newlines. ``None`` (the default) + selects the most compact representation. Using a positive integer indent + indents that many spaces per level. If *indent* is a string (such at '\t'), + that string is used to indent each level. If *separators* is an ``(item_separator, dict_separator)`` tuple, then it will be used instead of the default ``(', ', ': ')`` separators. ``(',', diff --git a/Lib/json/encoder.py b/Lib/json/encoder.py --- a/Lib/json/encoder.py +++ b/Lib/json/encoder.py @@ -233,7 +233,7 @@ if (_one_shot and c_make_encoder is not None - and not self.indent): + and self.indent is None): _iterencode = c_make_encoder( markers, self.default, _encoder, self.indent, self.key_separator, self.item_separator, self.sort_keys, diff --git a/Lib/test/json_tests/test_indent.py b/Lib/test/json_tests/test_indent.py --- a/Lib/test/json_tests/test_indent.py +++ b/Lib/test/json_tests/test_indent.py @@ -2,6 +2,7 @@ import json import textwrap +from io import StringIO class TestIndent(TestCase): def test_indent(self): @@ -43,3 +44,18 @@ self.assertEqual(h3, h) self.assertEqual(d2, expect.expandtabs(2)) self.assertEqual(d3, expect) + + def test_indent0(self): + h = {3: 1} + def check(indent, expected): + d1 = json.dumps(h, indent=indent) + self.assertEqual(d1, expected) + + sio = StringIO() + json.dump(h, sio, indent=indent) + self.assertEqual(sio.getvalue(), expected) + + # indent=0 should emit newlines + check(0, '{\n"3": 1\n}') + # indent=None is more compact + check(None, '{"3": 1}') diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -103,6 +103,9 @@ Library ------- +- Issue #10019: Fixed regression in json module where an indent of 0 stopped + adding newlines and acted instead like 'None'. + - Issue #11186: pydoc ignores a module if its name contains a surrogate character in the index of modules. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 13 03:35:44 2011 From: python-checkins at python.org (raymond.hettinger) Date: Wed, 13 Apr 2011 03:35:44 +0200 Subject: [Python-checkins] cpython (3.2): Issue 11718: Teach IDLE's open module dialog to find packages. Message-ID: http://hg.python.org/cpython/rev/27eda70c25b1 changeset: 69297:27eda70c25b1 branch: 3.2 parent: 69295:fe8bbaff5a27 user: Raymond Hettinger date: Tue Apr 12 18:30:14 2011 -0700 summary: Issue 11718: Teach IDLE's open module dialog to find packages. files: Lib/idlelib/EditorWindow.py | 11 +++++++++++ Misc/NEWS | 6 ++++++ 2 files changed, 17 insertions(+), 0 deletions(-) diff --git a/Lib/idlelib/EditorWindow.py b/Lib/idlelib/EditorWindow.py --- a/Lib/idlelib/EditorWindow.py +++ b/Lib/idlelib/EditorWindow.py @@ -50,6 +50,17 @@ path = module.__path__ except AttributeError: raise ImportError('No source for module ' + module.__name__) + if descr[2] != imp.PY_SOURCE: + # If all of the above fails and didn't raise an exception,fallback + # to a straight import which can find __init__.py in a package. + m = __import__(fullname) + try: + filename = m.__file__ + except AttributeError: + pass + else: + file = None + descr = os.path.splitext(filename), None, imp.PY_SOURCE return file, filename, descr class EditorWindow(object): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -224,6 +224,12 @@ - Issue #11268: Prevent Mac OS X Installer failure if Documentation package had previously been installed. +IDLE +---- + +- Issue #11718: IDLE's open module dialog couldn't find the __init__.py + file in a package. + Tools/Demos ----------- -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 13 03:35:45 2011 From: python-checkins at python.org (raymond.hettinger) Date: Wed, 13 Apr 2011 03:35:45 +0200 Subject: [Python-checkins] cpython: Issue 11718: Teach IDLE's open module dialog to find packages. Message-ID: http://hg.python.org/cpython/rev/65c39e9eb262 changeset: 69298:65c39e9eb262 parent: 69296:2d0d0850335e user: Raymond Hettinger date: Tue Apr 12 18:30:58 2011 -0700 summary: Issue 11718: Teach IDLE's open module dialog to find packages. files: Lib/idlelib/EditorWindow.py | 11 +++++++++++ 1 files changed, 11 insertions(+), 0 deletions(-) diff --git a/Lib/idlelib/EditorWindow.py b/Lib/idlelib/EditorWindow.py --- a/Lib/idlelib/EditorWindow.py +++ b/Lib/idlelib/EditorWindow.py @@ -50,6 +50,17 @@ path = module.__path__ except AttributeError: raise ImportError('No source for module ' + module.__name__) + if descr[2] != imp.PY_SOURCE: + # If all of the above fails and didn't raise an exception,fallback + # to a straight import which can find __init__.py in a package. + m = __import__(fullname) + try: + filename = m.__file__ + except AttributeError: + pass + else: + file = None + descr = os.path.splitext(filename), None, imp.PY_SOURCE return file, filename, descr class EditorWindow(object): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 13 03:35:48 2011 From: python-checkins at python.org (raymond.hettinger) Date: Wed, 13 Apr 2011 03:35:48 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): merge Message-ID: http://hg.python.org/cpython/rev/c8d075051e88 changeset: 69299:c8d075051e88 parent: 69298:65c39e9eb262 parent: 69297:27eda70c25b1 user: Raymond Hettinger date: Tue Apr 12 18:35:16 2011 -0700 summary: merge files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 13 03:43:31 2011 From: python-checkins at python.org (senthil.kumaran) Date: Wed, 13 Apr 2011 03:43:31 +0200 Subject: [Python-checkins] cpython (3.1): Update the News for the fix to Issue11703. Message-ID: http://hg.python.org/cpython/rev/8ee48ec69844 changeset: 69300:8ee48ec69844 branch: 3.1 parent: 69289:1ea945be3d09 user: Senthil Kumaran date: Wed Apr 13 09:21:01 2011 +0800 summary: Update the News for the fix to Issue11703. files: Misc/NEWS | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -51,6 +51,9 @@ Library ------- +- Issue #11703 - urllib2.geturl() does not return correct url when the original + url contains #fragment. + - Issue #5162: Treat services like frozen executables to allow child spawning from multiprocessing.forking on Windows. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 13 03:43:32 2011 From: python-checkins at python.org (senthil.kumaran) Date: Wed, 13 Apr 2011 03:43:32 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): merge from 3.1 Message-ID: http://hg.python.org/cpython/rev/b151b192b39c changeset: 69301:b151b192b39c branch: 3.2 parent: 69290:d25c2812b0d8 parent: 69300:8ee48ec69844 user: Senthil Kumaran date: Wed Apr 13 09:21:42 2011 +0800 summary: merge from 3.1 files: Misc/NEWS | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -53,6 +53,9 @@ Library ------- +- Issue #11703 - urllib2.geturl() does not return correct url when the original + url contains #fragment. + - Issue #5162: Treat services like frozen executables to allow child spawning from multiprocessing.forking on Windows. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 13 03:43:33 2011 From: python-checkins at python.org (senthil.kumaran) Date: Wed, 13 Apr 2011 03:43:33 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> 3.2): merge update Message-ID: http://hg.python.org/cpython/rev/f7acd95d43f8 changeset: 69302:f7acd95d43f8 branch: 3.2 parent: 69301:b151b192b39c parent: 69295:fe8bbaff5a27 user: Senthil Kumaran date: Wed Apr 13 09:34:21 2011 +0800 summary: merge update files: Doc/library/json.rst | 8 ++++---- Lib/json/encoder.py | 2 +- Lib/test/json_tests/test_indent.py | 16 ++++++++++++++++ Misc/NEWS | 3 +++ 4 files changed, 24 insertions(+), 5 deletions(-) diff --git a/Doc/library/json.rst b/Doc/library/json.rst --- a/Doc/library/json.rst +++ b/Doc/library/json.rst @@ -136,10 +136,10 @@ If *indent* is a non-negative integer or string, then JSON array elements and object members will be pretty-printed with that indent level. An indent level - of 0 or ``""`` will only insert newlines. ``None`` (the default) selects the - most compact representation. Using an integer indent indents that many spaces - per level. If *indent* is a string (such at '\t'), that string is used to indent - each level. + of 0, negative, or ``""`` will only insert newlines. ``None`` (the default) + selects the most compact representation. Using a positive integer indent + indents that many spaces per level. If *indent* is a string (such at '\t'), + that string is used to indent each level. If *separators* is an ``(item_separator, dict_separator)`` tuple, then it will be used instead of the default ``(', ', ': ')`` separators. ``(',', diff --git a/Lib/json/encoder.py b/Lib/json/encoder.py --- a/Lib/json/encoder.py +++ b/Lib/json/encoder.py @@ -233,7 +233,7 @@ if (_one_shot and c_make_encoder is not None - and not self.indent): + and self.indent is None): _iterencode = c_make_encoder( markers, self.default, _encoder, self.indent, self.key_separator, self.item_separator, self.sort_keys, diff --git a/Lib/test/json_tests/test_indent.py b/Lib/test/json_tests/test_indent.py --- a/Lib/test/json_tests/test_indent.py +++ b/Lib/test/json_tests/test_indent.py @@ -2,6 +2,7 @@ import json import textwrap +from io import StringIO class TestIndent(TestCase): def test_indent(self): @@ -43,3 +44,18 @@ self.assertEqual(h3, h) self.assertEqual(d2, expect.expandtabs(2)) self.assertEqual(d3, expect) + + def test_indent0(self): + h = {3: 1} + def check(indent, expected): + d1 = json.dumps(h, indent=indent) + self.assertEqual(d1, expected) + + sio = StringIO() + json.dump(h, sio, indent=indent) + self.assertEqual(sio.getvalue(), expected) + + # indent=0 should emit newlines + check(0, '{\n"3": 1\n}') + # indent=None is more compact + check(None, '{"3": 1}') diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -55,6 +55,9 @@ - Issue #11703 - urllib2.geturl() does not return correct url when the original url contains #fragment. + +- Issue #10019: Fixed regression in json module where an indent of 0 stopped + adding newlines and acted instead like 'None'. - Issue #5162: Treat services like frozen executables to allow child spawning from multiprocessing.forking on Windows. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 13 03:43:36 2011 From: python-checkins at python.org (senthil.kumaran) Date: Wed, 13 Apr 2011 03:43:36 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.1): Merge updates Message-ID: http://hg.python.org/cpython/rev/29868f95519d changeset: 69303:29868f95519d branch: 3.1 parent: 69300:8ee48ec69844 parent: 69294:4a1048257995 user: Senthil Kumaran date: Wed Apr 13 09:35:37 2011 +0800 summary: Merge updates files: Doc/library/json.rst | 6 +++--- Lib/json/encoder.py | 2 +- Lib/json/tests/test_indent.py | 16 ++++++++++++++++ Misc/NEWS | 3 +++ 4 files changed, 23 insertions(+), 4 deletions(-) diff --git a/Doc/library/json.rst b/Doc/library/json.rst --- a/Doc/library/json.rst +++ b/Doc/library/json.rst @@ -135,9 +135,9 @@ using the JavaScript equivalents (``NaN``, ``Infinity``, ``-Infinity``). If *indent* is a non-negative integer, then JSON array elements and object - members will be pretty-printed with that indent level. An indent level of 0 - will only insert newlines. ``None`` (the default) selects the most compact - representation. + members will be pretty-printed with that indent level. An indent level of 0, + or negative, will only insert newlines. ``None`` (the default) selects the + most compact representation. If *separators* is an ``(item_separator, dict_separator)`` tuple, then it will be used instead of the default ``(', ', ': ')`` separators. ``(',', diff --git a/Lib/json/encoder.py b/Lib/json/encoder.py --- a/Lib/json/encoder.py +++ b/Lib/json/encoder.py @@ -233,7 +233,7 @@ if (_one_shot and c_make_encoder is not None - and not self.indent): + and self.indent is None): _iterencode = c_make_encoder( markers, self.default, _encoder, self.indent, self.key_separator, self.item_separator, self.sort_keys, diff --git a/Lib/json/tests/test_indent.py b/Lib/json/tests/test_indent.py --- a/Lib/json/tests/test_indent.py +++ b/Lib/json/tests/test_indent.py @@ -2,6 +2,7 @@ import json import textwrap +from io import StringIO class TestIndent(TestCase): def test_indent(self): @@ -39,3 +40,18 @@ self.assertEqual(h1, h) self.assertEqual(h2, h) self.assertEqual(d2, expect) + + def test_indent0(self): + h = {3: 1} + def check(indent, expected): + d1 = json.dumps(h, indent=indent) + self.assertEqual(d1, expected) + + sio = StringIO() + json.dump(h, sio, indent=indent) + self.assertEqual(sio.getvalue(), expected) + + # indent=0 should emit newlines + check(0, '{\n"3": 1\n}') + # indent=None is more compact + check(None, '{"3": 1}') diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -53,6 +53,9 @@ - Issue #11703 - urllib2.geturl() does not return correct url when the original url contains #fragment. + +- Issue #10019: Fixed regression in json module where an indent of 0 stopped + adding newlines and acted instead like 'None'. - Issue #5162: Treat services like frozen executables to allow child spawning from multiprocessing.forking on Windows. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 13 03:43:38 2011 From: python-checkins at python.org (senthil.kumaran) Date: Wed, 13 Apr 2011 03:43:38 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): Merge update. Message-ID: http://hg.python.org/cpython/rev/35388341060d changeset: 69304:35388341060d branch: 3.2 parent: 69302:f7acd95d43f8 parent: 69303:29868f95519d user: Senthil Kumaran date: Wed Apr 13 09:36:31 2011 +0800 summary: Merge update. files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 13 03:43:43 2011 From: python-checkins at python.org (senthil.kumaran) Date: Wed, 13 Apr 2011 03:43:43 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): merge from 3.2 Message-ID: http://hg.python.org/cpython/rev/35b16d49c0b1 changeset: 69305:35b16d49c0b1 parent: 69296:2d0d0850335e parent: 69304:35388341060d user: Senthil Kumaran date: Wed Apr 13 09:37:39 2011 +0800 summary: merge from 3.2 files: Misc/NEWS | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -103,6 +103,9 @@ Library ------- +- Issue #11703 - urllib2.geturl() does not return correct url when the original + url contains #fragment. + - Issue #10019: Fixed regression in json module where an indent of 0 stopped adding newlines and acted instead like 'None'. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 13 03:43:48 2011 From: python-checkins at python.org (senthil.kumaran) Date: Wed, 13 Apr 2011 03:43:48 +0200 Subject: [Python-checkins] cpython (merge default -> default): merge from push conflict. Message-ID: http://hg.python.org/cpython/rev/a4d1a3e0f7bd changeset: 69306:a4d1a3e0f7bd parent: 69305:35b16d49c0b1 parent: 69299:c8d075051e88 user: Senthil Kumaran date: Wed Apr 13 09:38:51 2011 +0800 summary: merge from push conflict. files: Lib/idlelib/EditorWindow.py | 11 +++++++++++ 1 files changed, 11 insertions(+), 0 deletions(-) diff --git a/Lib/idlelib/EditorWindow.py b/Lib/idlelib/EditorWindow.py --- a/Lib/idlelib/EditorWindow.py +++ b/Lib/idlelib/EditorWindow.py @@ -50,6 +50,17 @@ path = module.__path__ except AttributeError: raise ImportError('No source for module ' + module.__name__) + if descr[2] != imp.PY_SOURCE: + # If all of the above fails and didn't raise an exception,fallback + # to a straight import which can find __init__.py in a package. + m = __import__(fullname) + try: + filename = m.__file__ + except AttributeError: + pass + else: + file = None + descr = os.path.splitext(filename), None, imp.PY_SOURCE return file, filename, descr class EditorWindow(object): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 13 03:43:49 2011 From: python-checkins at python.org (senthil.kumaran) Date: Wed, 13 Apr 2011 03:43:49 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> 3.2): merge from push conflict. Message-ID: http://hg.python.org/cpython/rev/104429122abb changeset: 69307:104429122abb branch: 3.2 parent: 69304:35388341060d parent: 69297:27eda70c25b1 user: Senthil Kumaran date: Wed Apr 13 09:39:35 2011 +0800 summary: merge from push conflict. files: Lib/idlelib/EditorWindow.py | 11 +++++++++++ Misc/NEWS | 6 ++++++ 2 files changed, 17 insertions(+), 0 deletions(-) diff --git a/Lib/idlelib/EditorWindow.py b/Lib/idlelib/EditorWindow.py --- a/Lib/idlelib/EditorWindow.py +++ b/Lib/idlelib/EditorWindow.py @@ -50,6 +50,17 @@ path = module.__path__ except AttributeError: raise ImportError('No source for module ' + module.__name__) + if descr[2] != imp.PY_SOURCE: + # If all of the above fails and didn't raise an exception,fallback + # to a straight import which can find __init__.py in a package. + m = __import__(fullname) + try: + filename = m.__file__ + except AttributeError: + pass + else: + file = None + descr = os.path.splitext(filename), None, imp.PY_SOURCE return file, filename, descr class EditorWindow(object): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -227,6 +227,12 @@ - Issue #11268: Prevent Mac OS X Installer failure if Documentation package had previously been installed. +IDLE +---- + +- Issue #11718: IDLE's open module dialog couldn't find the __init__.py + file in a package. + Tools/Demos ----------- -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 13 03:43:50 2011 From: python-checkins at python.org (senthil.kumaran) Date: Wed, 13 Apr 2011 03:43:50 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): merge. Message-ID: http://hg.python.org/cpython/rev/ac54877574cb changeset: 69308:ac54877574cb parent: 69306:a4d1a3e0f7bd parent: 69307:104429122abb user: Senthil Kumaran date: Wed Apr 13 09:43:05 2011 +0800 summary: merge. files: Misc/NEWS | 9 ++++++++- 1 files changed, 8 insertions(+), 1 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -425,8 +425,15 @@ - Issue #11268: Prevent Mac OS X Installer failure if Documentation package had previously been installed. - + - Issue #11495: OSF support is eliminated. It was deprecated in Python 3.2. + + +IDLE +---- + +- Issue #11718: IDLE's open module dialog couldn't find the __init__.py + file in a package. Tools/Demos ----------- -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 13 03:47:53 2011 From: python-checkins at python.org (senthil.kumaran) Date: Wed, 13 Apr 2011 03:47:53 +0200 Subject: [Python-checkins] cpython (2.7): update news in 2.7 for Issue #11703 Message-ID: http://hg.python.org/cpython/rev/502bb809b03b changeset: 69309:502bb809b03b branch: 2.7 parent: 69293:8264f68e8251 user: Senthil Kumaran date: Wed Apr 13 09:47:20 2011 +0800 summary: update news in 2.7 for Issue #11703 files: Misc/NEWS | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -51,6 +51,9 @@ Library ------- +- Issue #11703 - urllib2.geturl() does not return correct url when the original + url contains #fragment. + - Issue #10019: Fixed regression in json module where an indent of 0 stopped adding newlines and acted instead like 'None'. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 13 03:54:59 2011 From: python-checkins at python.org (raymond.hettinger) Date: Wed, 13 Apr 2011 03:54:59 +0200 Subject: [Python-checkins] cpython (2.7): Issue 11718: Teach IDLE's open module dialog to find packages. Message-ID: http://hg.python.org/cpython/rev/e391f7005b0f changeset: 69310:e391f7005b0f branch: 2.7 user: Raymond Hettinger date: Tue Apr 12 18:54:46 2011 -0700 summary: Issue 11718: Teach IDLE's open module dialog to find packages. files: Lib/idlelib/EditorWindow.py | 15 +++++++++++++++ Misc/NEWS | 6 ++++++ 2 files changed, 21 insertions(+), 0 deletions(-) diff --git a/Lib/idlelib/EditorWindow.py b/Lib/idlelib/EditorWindow.py --- a/Lib/idlelib/EditorWindow.py +++ b/Lib/idlelib/EditorWindow.py @@ -48,6 +48,21 @@ path = module.__path__ except AttributeError: raise ImportError, 'No source for module ' + module.__name__ + if descr[2] != imp.PY_SOURCE: + # If all of the above fails and didn't raise an exception,fallback + # to a straight import which can find __init__.py in a package. + m = __import__(fullname) + try: + filename = m.__file__ + except AttributeError: + pass + else: + file = None + base, ext = os.path.splitext(filename) + if ext == '.pyc': + ext = '.py' + filename = base + ext + descr = filename, None, imp.PY_SOURCE return file, filename, descr class EditorWindow(object): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -336,6 +336,12 @@ - Issue #1099: Fix the build on MacOSX when building a framework with pydebug using GCC 4.0. +IDLE +---- + +- Issue #11718: IDLE's open module dialog couldn't find the __init__.py + file in a package. + Tests ----- -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 13 03:59:08 2011 From: python-checkins at python.org (raymond.hettinger) Date: Wed, 13 Apr 2011 03:59:08 +0200 Subject: [Python-checkins] cpython (3.2): Fix nit. Message-ID: http://hg.python.org/cpython/rev/dfbbe4c1a7bb changeset: 69311:dfbbe4c1a7bb branch: 3.2 parent: 69307:104429122abb user: Raymond Hettinger date: Tue Apr 12 18:57:55 2011 -0700 summary: Fix nit. files: Lib/idlelib/EditorWindow.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/idlelib/EditorWindow.py b/Lib/idlelib/EditorWindow.py --- a/Lib/idlelib/EditorWindow.py +++ b/Lib/idlelib/EditorWindow.py @@ -60,7 +60,7 @@ pass else: file = None - descr = os.path.splitext(filename), None, imp.PY_SOURCE + descr = os.path.splitext(filename)[1], None, imp.PY_SOURCE return file, filename, descr class EditorWindow(object): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 13 03:59:09 2011 From: python-checkins at python.org (raymond.hettinger) Date: Wed, 13 Apr 2011 03:59:09 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge Message-ID: http://hg.python.org/cpython/rev/39047f8bd1d1 changeset: 69312:39047f8bd1d1 parent: 69308:ac54877574cb parent: 69311:dfbbe4c1a7bb user: Raymond Hettinger date: Tue Apr 12 18:58:40 2011 -0700 summary: Merge files: Lib/idlelib/EditorWindow.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/idlelib/EditorWindow.py b/Lib/idlelib/EditorWindow.py --- a/Lib/idlelib/EditorWindow.py +++ b/Lib/idlelib/EditorWindow.py @@ -60,7 +60,7 @@ pass else: file = None - descr = os.path.splitext(filename), None, imp.PY_SOURCE + descr = os.path.splitext(filename)[1], None, imp.PY_SOURCE return file, filename, descr class EditorWindow(object): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 13 04:38:16 2011 From: python-checkins at python.org (ezio.melotti) Date: Wed, 13 Apr 2011 04:38:16 +0200 Subject: [Python-checkins] cpython (2.7): #9233: Fix json.loads({}) to return a dict (instead of a list), when _json is Message-ID: http://hg.python.org/cpython/rev/d58c63ff5bb2 changeset: 69313:d58c63ff5bb2 branch: 2.7 parent: 69310:e391f7005b0f user: Ezio Melotti date: Wed Apr 13 05:37:29 2011 +0300 summary: #9233: Fix json.loads({}) to return a dict (instead of a list), when _json is not available. files: Lib/json/decoder.py | 6 ++++++ Lib/json/tests/test_decode.py | 5 +++++ Misc/NEWS | 5 ++++- 3 files changed, 15 insertions(+), 1 deletions(-) diff --git a/Lib/json/decoder.py b/Lib/json/decoder.py --- a/Lib/json/decoder.py +++ b/Lib/json/decoder.py @@ -161,6 +161,12 @@ nextchar = s[end:end + 1] # Trivial empty object if nextchar == '}': + if object_pairs_hook is not None: + result = object_pairs_hook(pairs) + return result, end + pairs = {} + if object_hook is not None: + pairs = object_hook(pairs) return pairs, end + 1 elif nextchar != '"': raise ValueError(errmsg("Expecting property name", s, end)) diff --git a/Lib/json/tests/test_decode.py b/Lib/json/tests/test_decode.py --- a/Lib/json/tests/test_decode.py +++ b/Lib/json/tests/test_decode.py @@ -23,6 +23,11 @@ rval = json.loads('{ "key" : "value" , "k":"v" }') self.assertEqual(rval, {"key":"value", "k":"v"}) + def test_empty_objects(self): + self.assertEqual(json.loads('{}'), {}) + self.assertEqual(json.loads('[]'), []) + self.assertEqual(json.loads('""'), "") + def test_object_pairs_hook(self): s = '{"xkd":1, "kcw":2, "art":3, "hxm":4, "qrt":5, "pad":6, "hoy":7}' p = [("xkd", 1), ("kcw", 2), ("art", 3), ("hxm", 4), diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -51,7 +51,10 @@ Library ------- -- Issue #11703 - urllib2.geturl() does not return correct url when the original +- Issue #9233: Fix json.loads('{}') to return a dict (instead of a list), when + _json is not available. + +- Issue #11703: urllib2.geturl() does not return correct url when the original url contains #fragment. - Issue #10019: Fixed regression in json module where an indent of 0 stopped -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Wed Apr 13 05:00:44 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Wed, 13 Apr 2011 05:00:44 +0200 Subject: [Python-checkins] Daily reference leaks (2d0d0850335e): sum=-56 Message-ID: results for 2d0d0850335e on branch "default" -------------------------------------------- test_pyexpat leaked [0, 0, -56] references, sum=-56 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflog2vTRp7', '-x'] From python-checkins at python.org Wed Apr 13 05:09:03 2011 From: python-checkins at python.org (alexander.belopolsky) Date: Wed, 13 Apr 2011 05:09:03 +0200 Subject: [Python-checkins] cpython (3.2): Issue #11830: Remove unnecessary introspection code in the decimal module. Message-ID: http://hg.python.org/cpython/rev/f5d5f3f4c081 changeset: 69314:f5d5f3f4c081 branch: 3.2 parent: 69311:dfbbe4c1a7bb user: Alexander Belopolsky date: Tue Apr 12 23:03:39 2011 -0400 summary: Issue #11830: Remove unnecessary introspection code in the decimal module. Forward ported changesets b4b1f557d563 and f4adc2926bf5 by Raymond Hettinger in branch '2.7'. files: Lib/decimal.py | 31 ++++++++++++++----------------- Misc/NEWS | 2 ++ 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/Lib/decimal.py b/Lib/decimal.py --- a/Lib/decimal.py +++ b/Lib/decimal.py @@ -1650,7 +1650,7 @@ self = _dec_from_triple(self._sign, '1', exp_min-1) digits = 0 rounding_method = self._pick_rounding_function[context.rounding] - changed = getattr(self, rounding_method)(digits) + changed = rounding_method(self, digits) coeff = self._int[:digits] or '0' if changed > 0: coeff = str(int(coeff)+1) @@ -1690,8 +1690,6 @@ # here self was representable to begin with; return unchanged return Decimal(self) - _pick_rounding_function = {} - # for each of the rounding functions below: # self is a finite, nonzero Decimal # prec is an integer satisfying 0 <= prec < len(self._int) @@ -1758,6 +1756,17 @@ else: return -self._round_down(prec) + _pick_rounding_function = dict( + ROUND_DOWN = _round_down, + ROUND_UP = _round_up, + ROUND_HALF_UP = _round_half_up, + ROUND_HALF_DOWN = _round_half_down, + ROUND_HALF_EVEN = _round_half_even, + ROUND_CEILING = _round_ceiling, + ROUND_FLOOR = _round_floor, + ROUND_05UP = _round_05up, + ) + def __round__(self, n=None): """Round self to the nearest integer, or to a given precision. @@ -2554,8 +2563,8 @@ if digits < 0: self = _dec_from_triple(self._sign, '1', exp-1) digits = 0 - this_function = getattr(self, self._pick_rounding_function[rounding]) - changed = this_function(digits) + this_function = self._pick_rounding_function[rounding] + changed = this_function(self, digits) coeff = self._int[:digits] or '0' if changed == 1: coeff = str(int(coeff)+1) @@ -3767,18 +3776,6 @@ ##### Context class ####################################################### - -# get rounding method function: -rounding_functions = [name for name in Decimal.__dict__.keys() - if name.startswith('_round_')] -for name in rounding_functions: - # name is like _round_half_even, goes to the global ROUND_HALF_EVEN value. - globalname = name[1:].upper() - val = globals()[globalname] - Decimal._pick_rounding_function[val] = name - -del name, val, globalname, rounding_functions - class _ContextManager(object): """Context manager class to support localcontext(). diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -53,6 +53,8 @@ Library ------- +- Issue #11830: Remove unnecessary introspection code in the decimal module. + - Issue #11703 - urllib2.geturl() does not return correct url when the original url contains #fragment. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 13 05:09:04 2011 From: python-checkins at python.org (alexander.belopolsky) Date: Wed, 13 Apr 2011 05:09:04 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge Message-ID: http://hg.python.org/cpython/rev/c2ea543f5a66 changeset: 69315:c2ea543f5a66 parent: 69312:39047f8bd1d1 parent: 69314:f5d5f3f4c081 user: Alexander Belopolsky date: Tue Apr 12 23:08:14 2011 -0400 summary: Merge files: Lib/decimal.py | 31 ++++++++++++++----------------- Misc/NEWS | 2 ++ 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/Lib/decimal.py b/Lib/decimal.py --- a/Lib/decimal.py +++ b/Lib/decimal.py @@ -1650,7 +1650,7 @@ self = _dec_from_triple(self._sign, '1', exp_min-1) digits = 0 rounding_method = self._pick_rounding_function[context.rounding] - changed = getattr(self, rounding_method)(digits) + changed = rounding_method(self, digits) coeff = self._int[:digits] or '0' if changed > 0: coeff = str(int(coeff)+1) @@ -1690,8 +1690,6 @@ # here self was representable to begin with; return unchanged return Decimal(self) - _pick_rounding_function = {} - # for each of the rounding functions below: # self is a finite, nonzero Decimal # prec is an integer satisfying 0 <= prec < len(self._int) @@ -1758,6 +1756,17 @@ else: return -self._round_down(prec) + _pick_rounding_function = dict( + ROUND_DOWN = _round_down, + ROUND_UP = _round_up, + ROUND_HALF_UP = _round_half_up, + ROUND_HALF_DOWN = _round_half_down, + ROUND_HALF_EVEN = _round_half_even, + ROUND_CEILING = _round_ceiling, + ROUND_FLOOR = _round_floor, + ROUND_05UP = _round_05up, + ) + def __round__(self, n=None): """Round self to the nearest integer, or to a given precision. @@ -2554,8 +2563,8 @@ if digits < 0: self = _dec_from_triple(self._sign, '1', exp-1) digits = 0 - this_function = getattr(self, self._pick_rounding_function[rounding]) - changed = this_function(digits) + this_function = self._pick_rounding_function[rounding] + changed = this_function(self, digits) coeff = self._int[:digits] or '0' if changed == 1: coeff = str(int(coeff)+1) @@ -3767,18 +3776,6 @@ ##### Context class ####################################################### - -# get rounding method function: -rounding_functions = [name for name in Decimal.__dict__.keys() - if name.startswith('_round_')] -for name in rounding_functions: - # name is like _round_half_even, goes to the global ROUND_HALF_EVEN value. - globalname = name[1:].upper() - val = globals()[globalname] - Decimal._pick_rounding_function[val] = name - -del name, val, globalname, rounding_functions - class _ContextManager(object): """Context manager class to support localcontext(). diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -103,6 +103,8 @@ Library ------- +- Issue #11830: Remove unnecessary introspection code in the decimal module. + - Issue #11703 - urllib2.geturl() does not return correct url when the original url contains #fragment. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 13 06:21:51 2011 From: python-checkins at python.org (ezio.melotti) Date: Wed, 13 Apr 2011 06:21:51 +0200 Subject: [Python-checkins] cpython (3.1): #9233: skip _json-specific tests when _json is not available. Message-ID: http://hg.python.org/cpython/rev/36e676a8541d changeset: 69316:36e676a8541d branch: 3.1 parent: 69303:29868f95519d user: Ezio Melotti date: Wed Apr 13 06:58:29 2011 +0300 summary: #9233: skip _json-specific tests when _json is not available. files: Lib/json/tests/test_scanstring.py | 8 +++++++- Lib/json/tests/test_speedups.py | 8 +++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/Lib/json/tests/test_scanstring.py b/Lib/json/tests/test_scanstring.py --- a/Lib/json/tests/test_scanstring.py +++ b/Lib/json/tests/test_scanstring.py @@ -1,14 +1,20 @@ import sys import decimal -from unittest import TestCase +from unittest import TestCase, skipUnless import json import json.decoder +try: + import _json +except ImportError: + _json = None + class TestScanString(TestCase): def test_py_scanstring(self): self._test_scanstring(json.decoder.py_scanstring) + @skipUnless(_json, 'test requires the _json module') def test_c_scanstring(self): if json.decoder.c_scanstring is not None: self._test_scanstring(json.decoder.c_scanstring) diff --git a/Lib/json/tests/test_speedups.py b/Lib/json/tests/test_speedups.py --- a/Lib/json/tests/test_speedups.py +++ b/Lib/json/tests/test_speedups.py @@ -1,8 +1,14 @@ import decimal -from unittest import TestCase +from unittest import TestCase, skipUnless from json import decoder, encoder, scanner +try: + import _json +except ImportError: + _json = None + + at skipUnless(_json, 'test requires the _json module') class TestSpeedups(TestCase): def test_scanstring(self): self.assertEqual(decoder.scanstring.__module__, "_json") -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 13 06:21:51 2011 From: python-checkins at python.org (ezio.melotti) Date: Wed, 13 Apr 2011 06:21:51 +0200 Subject: [Python-checkins] cpython (3.1): #9233: Fix json to work properly even when _json is not available. Message-ID: http://hg.python.org/cpython/rev/7019fc1a9663 changeset: 69317:7019fc1a9663 branch: 3.1 user: Ezio Melotti date: Wed Apr 13 07:04:18 2011 +0300 summary: #9233: Fix json to work properly even when _json is not available. files: Lib/json/decoder.py | 2 +- Lib/json/scanner.py | 1 + Misc/NEWS | 6 ++++-- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Lib/json/decoder.py b/Lib/json/decoder.py --- a/Lib/json/decoder.py +++ b/Lib/json/decoder.py @@ -214,7 +214,7 @@ pairs = object_hook(pairs) return pairs, end -def JSONArray(s_and_end, scan_once, context, _w=WHITESPACE.match): +def JSONArray(s_and_end, scan_once, _w=WHITESPACE.match, _ws=WHITESPACE_STR): s, end = s_and_end values = [] nextchar = s[end:end + 1] diff --git a/Lib/json/scanner.py b/Lib/json/scanner.py --- a/Lib/json/scanner.py +++ b/Lib/json/scanner.py @@ -22,6 +22,7 @@ parse_int = context.parse_int parse_constant = context.parse_constant object_hook = context.object_hook + object_pairs_hook = context.object_pairs_hook def _scan_once(string, idx): try: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -51,9 +51,11 @@ Library ------- -- Issue #11703 - urllib2.geturl() does not return correct url when the original +- Issue #9233: Fix json to work properly even when _json is not available. + +- Issue #11703: urllib2.geturl() does not return correct url when the original url contains #fragment. - + - Issue #10019: Fixed regression in json module where an indent of 0 stopped adding newlines and acted instead like 'None'. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 13 06:21:53 2011 From: python-checkins at python.org (ezio.melotti) Date: Wed, 13 Apr 2011 06:21:53 +0200 Subject: [Python-checkins] cpython (3.1): Remove unnecessary imports and use assertIs instead of assertTrue. Message-ID: http://hg.python.org/cpython/rev/ec6d881f5b02 changeset: 69318:ec6d881f5b02 branch: 3.1 user: Ezio Melotti date: Wed Apr 13 07:08:17 2011 +0300 summary: Remove unnecessary imports and use assertIs instead of assertTrue. files: Lib/json/tests/test_scanstring.py | 1 - Lib/json/tests/test_speedups.py | 7 +++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/Lib/json/tests/test_scanstring.py b/Lib/json/tests/test_scanstring.py --- a/Lib/json/tests/test_scanstring.py +++ b/Lib/json/tests/test_scanstring.py @@ -1,5 +1,4 @@ import sys -import decimal from unittest import TestCase, skipUnless import json diff --git a/Lib/json/tests/test_speedups.py b/Lib/json/tests/test_speedups.py --- a/Lib/json/tests/test_speedups.py +++ b/Lib/json/tests/test_speedups.py @@ -1,4 +1,3 @@ -import decimal from unittest import TestCase, skipUnless from json import decoder, encoder, scanner @@ -12,12 +11,12 @@ class TestSpeedups(TestCase): def test_scanstring(self): self.assertEqual(decoder.scanstring.__module__, "_json") - self.assertTrue(decoder.scanstring is decoder.c_scanstring) + self.assertIs(decoder.scanstring, decoder.c_scanstring) def test_encode_basestring_ascii(self): self.assertEqual(encoder.encode_basestring_ascii.__module__, "_json") - self.assertTrue(encoder.encode_basestring_ascii is - encoder.c_encode_basestring_ascii) + self.assertIs(encoder.encode_basestring_ascii, + encoder.c_encode_basestring_ascii) class TestDecode(TestCase): def test_make_scanner(self): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 13 06:21:56 2011 From: python-checkins at python.org (ezio.melotti) Date: Wed, 13 Apr 2011 06:21:56 +0200 Subject: [Python-checkins] cpython (3.1): #9233: Fix json.loads({}) to return a dict (instead of a list), when _json is Message-ID: http://hg.python.org/cpython/rev/a220458179ed changeset: 69319:a220458179ed branch: 3.1 user: Ezio Melotti date: Wed Apr 13 07:10:13 2011 +0300 summary: #9233: Fix json.loads({}) to return a dict (instead of a list), when _json is not available. files: Lib/json/decoder.py | 6 ++++++ Lib/json/tests/test_decode.py | 5 +++++ 2 files changed, 11 insertions(+), 0 deletions(-) diff --git a/Lib/json/decoder.py b/Lib/json/decoder.py --- a/Lib/json/decoder.py +++ b/Lib/json/decoder.py @@ -161,6 +161,12 @@ nextchar = s[end:end + 1] # Trivial empty object if nextchar == '}': + if object_pairs_hook is not None: + result = object_pairs_hook(pairs) + return result, end + pairs = {} + if object_hook is not None: + pairs = object_hook(pairs) return pairs, end + 1 elif nextchar != '"': raise ValueError(errmsg("Expecting property name", s, end)) diff --git a/Lib/json/tests/test_decode.py b/Lib/json/tests/test_decode.py --- a/Lib/json/tests/test_decode.py +++ b/Lib/json/tests/test_decode.py @@ -16,6 +16,11 @@ self.assertTrue(isinstance(rval, float)) self.assertEqual(rval, 1.0) + def test_empty_objects(self): + self.assertEqual(json.loads('{}'), {}) + self.assertEqual(json.loads('[]'), []) + self.assertEqual(json.loads('""'), "") + def test_object_pairs_hook(self): s = '{"xkd":1, "kcw":2, "art":3, "hxm":4, "qrt":5, "pad":6, "hoy":7}' p = [("xkd", 1), ("kcw", 2), ("art", 3), ("hxm", 4), -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 13 06:21:57 2011 From: python-checkins at python.org (ezio.melotti) Date: Wed, 13 Apr 2011 06:21:57 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): Merge with 3.1. Message-ID: http://hg.python.org/cpython/rev/b279611146d7 changeset: 69320:b279611146d7 branch: 3.2 parent: 69314:f5d5f3f4c081 parent: 69319:a220458179ed user: Ezio Melotti date: Wed Apr 13 07:18:24 2011 +0300 summary: Merge with 3.1. files: Lib/json/decoder.py | 6 ++++++ Lib/test/json_tests/test_decode.py | 5 +++++ Lib/test/json_tests/test_scanstring.py | 9 +++++++-- Lib/test/json_tests/test_speedups.py | 14 ++++++++++---- Misc/NEWS | 11 +++++++---- 5 files changed, 35 insertions(+), 10 deletions(-) diff --git a/Lib/json/decoder.py b/Lib/json/decoder.py --- a/Lib/json/decoder.py +++ b/Lib/json/decoder.py @@ -165,6 +165,12 @@ nextchar = s[end:end + 1] # Trivial empty object if nextchar == '}': + if object_pairs_hook is not None: + result = object_pairs_hook(pairs) + return result, end + pairs = {} + if object_hook is not None: + pairs = object_hook(pairs) return pairs, end + 1 elif nextchar != '"': raise ValueError(errmsg("Expecting property name", s, end)) diff --git a/Lib/test/json_tests/test_decode.py b/Lib/test/json_tests/test_decode.py --- a/Lib/test/json_tests/test_decode.py +++ b/Lib/test/json_tests/test_decode.py @@ -31,6 +31,11 @@ self.assertTrue(isinstance(rval, float)) self.assertEqual(rval, 1.0) + def test_empty_objects(self): + self.assertEqual(json.loads('{}'), {}) + self.assertEqual(json.loads('[]'), []) + self.assertEqual(json.loads('""'), "") + def test_object_pairs_hook(self): s = '{"xkd":1, "kcw":2, "art":3, "hxm":4, "qrt":5, "pad":6, "hoy":7}' p = [("xkd", 1), ("kcw", 2), ("art", 3), ("hxm", 4), diff --git a/Lib/test/json_tests/test_scanstring.py b/Lib/test/json_tests/test_scanstring.py --- a/Lib/test/json_tests/test_scanstring.py +++ b/Lib/test/json_tests/test_scanstring.py @@ -1,14 +1,19 @@ import sys -import decimal -from unittest import TestCase +from unittest import TestCase, skipUnless import json import json.decoder +try: + import _json +except ImportError: + _json = None + class TestScanString(TestCase): def test_py_scanstring(self): self._test_scanstring(json.decoder.py_scanstring) + @skipUnless(_json, 'test requires the _json module') def test_c_scanstring(self): if json.decoder.c_scanstring is not None: self._test_scanstring(json.decoder.c_scanstring) diff --git a/Lib/test/json_tests/test_speedups.py b/Lib/test/json_tests/test_speedups.py --- a/Lib/test/json_tests/test_speedups.py +++ b/Lib/test/json_tests/test_speedups.py @@ -1,16 +1,22 @@ -from unittest import TestCase +from unittest import TestCase, skipUnless from json import decoder, encoder, scanner +try: + import _json +except ImportError: + _json = None + + at skipUnless(_json, 'test requires the _json module') class TestSpeedups(TestCase): def test_scanstring(self): self.assertEqual(decoder.scanstring.__module__, "_json") - self.assertTrue(decoder.scanstring is decoder.c_scanstring) + self.assertIs(decoder.scanstring, decoder.c_scanstring) def test_encode_basestring_ascii(self): self.assertEqual(encoder.encode_basestring_ascii.__module__, "_json") - self.assertTrue(encoder.encode_basestring_ascii is - encoder.c_encode_basestring_ascii) + self.assertIs(encoder.encode_basestring_ascii, + encoder.c_encode_basestring_ascii) class TestDecode(TestCase): def test_make_scanner(self): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -53,11 +53,14 @@ Library ------- -- Issue #11830: Remove unnecessary introspection code in the decimal module. - -- Issue #11703 - urllib2.geturl() does not return correct url when the original +- Issue #9233: Fix json.loads('{}') to return a dict (instead of a list), when + _json is not available. + +- Issue #11830: Remove unnecessary introspection code in the decimal module. + +- Issue #11703: urllib2.geturl() does not return correct url when the original url contains #fragment. - + - Issue #10019: Fixed regression in json module where an indent of 0 stopped adding newlines and acted instead like 'None'. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 13 06:21:59 2011 From: python-checkins at python.org (ezio.melotti) Date: Wed, 13 Apr 2011 06:21:59 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge with 3.2. Message-ID: http://hg.python.org/cpython/rev/e8e3f2b72a32 changeset: 69321:e8e3f2b72a32 parent: 69315:c2ea543f5a66 parent: 69320:b279611146d7 user: Ezio Melotti date: Wed Apr 13 07:21:24 2011 +0300 summary: Merge with 3.2. files: Lib/json/decoder.py | 6 ++++++ Lib/test/json_tests/test_decode.py | 5 +++++ Lib/test/json_tests/test_scanstring.py | 9 +++++++-- Lib/test/json_tests/test_speedups.py | 14 ++++++++++---- Misc/NEWS | 11 +++++++---- 5 files changed, 35 insertions(+), 10 deletions(-) diff --git a/Lib/json/decoder.py b/Lib/json/decoder.py --- a/Lib/json/decoder.py +++ b/Lib/json/decoder.py @@ -165,6 +165,12 @@ nextchar = s[end:end + 1] # Trivial empty object if nextchar == '}': + if object_pairs_hook is not None: + result = object_pairs_hook(pairs) + return result, end + pairs = {} + if object_hook is not None: + pairs = object_hook(pairs) return pairs, end + 1 elif nextchar != '"': raise ValueError(errmsg("Expecting property name", s, end)) diff --git a/Lib/test/json_tests/test_decode.py b/Lib/test/json_tests/test_decode.py --- a/Lib/test/json_tests/test_decode.py +++ b/Lib/test/json_tests/test_decode.py @@ -31,6 +31,11 @@ self.assertTrue(isinstance(rval, float)) self.assertEqual(rval, 1.0) + def test_empty_objects(self): + self.assertEqual(json.loads('{}'), {}) + self.assertEqual(json.loads('[]'), []) + self.assertEqual(json.loads('""'), "") + def test_object_pairs_hook(self): s = '{"xkd":1, "kcw":2, "art":3, "hxm":4, "qrt":5, "pad":6, "hoy":7}' p = [("xkd", 1), ("kcw", 2), ("art", 3), ("hxm", 4), diff --git a/Lib/test/json_tests/test_scanstring.py b/Lib/test/json_tests/test_scanstring.py --- a/Lib/test/json_tests/test_scanstring.py +++ b/Lib/test/json_tests/test_scanstring.py @@ -1,14 +1,19 @@ import sys -import decimal -from unittest import TestCase +from unittest import TestCase, skipUnless import json import json.decoder +try: + import _json +except ImportError: + _json = None + class TestScanString(TestCase): def test_py_scanstring(self): self._test_scanstring(json.decoder.py_scanstring) + @skipUnless(_json, 'test requires the _json module') def test_c_scanstring(self): if json.decoder.c_scanstring is not None: self._test_scanstring(json.decoder.c_scanstring) diff --git a/Lib/test/json_tests/test_speedups.py b/Lib/test/json_tests/test_speedups.py --- a/Lib/test/json_tests/test_speedups.py +++ b/Lib/test/json_tests/test_speedups.py @@ -1,16 +1,22 @@ -from unittest import TestCase +from unittest import TestCase, skipUnless from json import decoder, encoder, scanner +try: + import _json +except ImportError: + _json = None + + at skipUnless(_json, 'test requires the _json module') class TestSpeedups(TestCase): def test_scanstring(self): self.assertEqual(decoder.scanstring.__module__, "_json") - self.assertTrue(decoder.scanstring is decoder.c_scanstring) + self.assertIs(decoder.scanstring, decoder.c_scanstring) def test_encode_basestring_ascii(self): self.assertEqual(encoder.encode_basestring_ascii.__module__, "_json") - self.assertTrue(encoder.encode_basestring_ascii is - encoder.c_encode_basestring_ascii) + self.assertIs(encoder.encode_basestring_ascii, + encoder.c_encode_basestring_ascii) class TestDecode(TestCase): def test_make_scanner(self): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -103,11 +103,14 @@ Library ------- -- Issue #11830: Remove unnecessary introspection code in the decimal module. - -- Issue #11703 - urllib2.geturl() does not return correct url when the original +- Issue #9233: Fix json.loads('{}') to return a dict (instead of a list), when + _json is not available. + +- Issue #11830: Remove unnecessary introspection code in the decimal module. + +- Issue #11703: urllib2.geturl() does not return correct url when the original url contains #fragment. - + - Issue #10019: Fixed regression in json module where an indent of 0 stopped adding newlines and acted instead like 'None'. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 13 07:38:09 2011 From: python-checkins at python.org (nadeem.vawda) Date: Wed, 13 Apr 2011 07:38:09 +0200 Subject: [Python-checkins] cpython: Add Misc/NEWS entry for changeset 0010cc5f22d4. Message-ID: http://hg.python.org/cpython/rev/e67eb5ec5627 changeset: 69322:e67eb5ec5627 user: Nadeem Vawda date: Wed Apr 13 07:35:29 2011 +0200 summary: Add Misc/NEWS entry for changeset 0010cc5f22d4. files: Misc/NEWS | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -103,6 +103,8 @@ Library ------- +- The bz2 module now handles 4GiB+ input buffers correctly. + - Issue #9233: Fix json.loads('{}') to return a dict (instead of a list), when _json is not available. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 13 15:45:27 2011 From: python-checkins at python.org (ezio.melotti) Date: Wed, 13 Apr 2011 15:45:27 +0200 Subject: [Python-checkins] cpython (3.1): Fix typo in docstring. Message-ID: http://hg.python.org/cpython/rev/bbed01a7d0d1 changeset: 69323:bbed01a7d0d1 branch: 3.1 parent: 69319:a220458179ed user: Ezio Melotti date: Wed Apr 13 16:43:21 2011 +0300 summary: Fix typo in docstring. files: Lib/email/header.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/email/header.py b/Lib/email/header.py --- a/Lib/email/header.py +++ b/Lib/email/header.py @@ -281,7 +281,7 @@ 75-character length limit on any given encoded header field, so line-wrapping must be performed, even with double-byte character sets. - Optional maxlinelen specifies the maxiumum length of each generated + Optional maxlinelen specifies the maximum length of each generated line, exclusive of the linesep string. Individual lines may be longer than maxlinelen if a folding point cannot be found. The first line will be shorter by the length of the header name plus ": " if a header -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 13 15:45:29 2011 From: python-checkins at python.org (ezio.melotti) Date: Wed, 13 Apr 2011 15:45:29 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): Merge with 3.1. Message-ID: http://hg.python.org/cpython/rev/0eaa8b38e18b changeset: 69324:0eaa8b38e18b branch: 3.2 parent: 69320:b279611146d7 parent: 69323:bbed01a7d0d1 user: Ezio Melotti date: Wed Apr 13 16:44:18 2011 +0300 summary: Merge with 3.1. files: Lib/email/header.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/email/header.py b/Lib/email/header.py --- a/Lib/email/header.py +++ b/Lib/email/header.py @@ -292,7 +292,7 @@ 75-character length limit on any given encoded header field, so line-wrapping must be performed, even with double-byte character sets. - Optional maxlinelen specifies the maxiumum length of each generated + Optional maxlinelen specifies the maximum length of each generated line, exclusive of the linesep string. Individual lines may be longer than maxlinelen if a folding point cannot be found. The first line will be shorter by the length of the header name plus ": " if a header -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 13 15:45:30 2011 From: python-checkins at python.org (ezio.melotti) Date: Wed, 13 Apr 2011 15:45:30 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge with 3.2. Message-ID: http://hg.python.org/cpython/rev/e96a1b4980b2 changeset: 69325:e96a1b4980b2 parent: 69322:e67eb5ec5627 parent: 69324:0eaa8b38e18b user: Ezio Melotti date: Wed Apr 13 16:45:00 2011 +0300 summary: Merge with 3.2. files: Lib/email/header.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/email/header.py b/Lib/email/header.py --- a/Lib/email/header.py +++ b/Lib/email/header.py @@ -292,7 +292,7 @@ 75-character length limit on any given encoded header field, so line-wrapping must be performed, even with double-byte character sets. - Optional maxlinelen specifies the maxiumum length of each generated + Optional maxlinelen specifies the maximum length of each generated line, exclusive of the linesep string. Individual lines may be longer than maxlinelen if a folding point cannot be found. The first line will be shorter by the length of the header name plus ": " if a header -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 13 19:11:10 2011 From: python-checkins at python.org (nadeem.vawda) Date: Wed, 13 Apr 2011 19:11:10 +0200 Subject: [Python-checkins] cpython: Remove dead code in gzip. Message-ID: http://hg.python.org/cpython/rev/9bc342724319 changeset: 69326:9bc342724319 user: Nadeem Vawda date: Wed Apr 13 18:57:40 2011 +0200 summary: Remove dead code in gzip. These functions appear to be holdovers from the 2.x code, intended to handle problems with CRC signedness. files: Lib/gzip.py | 12 ------------ 1 files changed, 0 insertions(+), 12 deletions(-) diff --git a/Lib/gzip.py b/Lib/gzip.py --- a/Lib/gzip.py +++ b/Lib/gzip.py @@ -16,18 +16,6 @@ READ, WRITE = 1, 2 -def U32(i): - """Return i as an unsigned integer, assuming it fits in 32 bits. - If it's >= 2GB when viewed as a 32-bit unsigned int, return a long. - """ - if i < 0: - i += 1 << 32 - return i - -def LOWU32(i): - """Return the low-order 32 bits, as a non-negative int""" - return i & 0xFFFFFFFF - def write32u(output, value): # The L format writes the bit pattern correctly whether signed # or unsigned. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 13 20:16:08 2011 From: python-checkins at python.org (raymond.hettinger) Date: Wed, 13 Apr 2011 20:16:08 +0200 Subject: [Python-checkins] cpython (2.7): Issue 3051: make pure python code pass the same tests as the C version. Message-ID: http://hg.python.org/cpython/rev/103a2eb61069 changeset: 69327:103a2eb61069 branch: 2.7 parent: 69313:d58c63ff5bb2 user: Raymond Hettinger date: Wed Apr 13 11:15:58 2011 -0700 summary: Issue 3051: make pure python code pass the same tests as the C version. files: Lib/heapq.py | 20 ++++++++++++-------- Lib/test/test_heapq.py | 16 +++++----------- 2 files changed, 17 insertions(+), 19 deletions(-) diff --git a/Lib/heapq.py b/Lib/heapq.py --- a/Lib/heapq.py +++ b/Lib/heapq.py @@ -133,6 +133,11 @@ from operator import itemgetter import bisect +def cmp_lt(x, y): + # Use __lt__ if available; otherwise, try __le__. + # In Py3.x, only __lt__ will be called. + return (x < y) if hasattr(x, '__lt__') else (not y <= x) + def heappush(heap, item): """Push item onto heap, maintaining the heap invariant.""" heap.append(item) @@ -167,7 +172,7 @@ def heappushpop(heap, item): """Fast version of a heappush followed by a heappop.""" - if heap and heap[0] < item: + if heap and cmp_lt(heap[0], item): item, heap[0] = heap[0], item _siftup(heap, 0) return item @@ -215,11 +220,10 @@ pop = result.pop los = result[-1] # los --> Largest of the nsmallest for elem in it: - if los <= elem: - continue - insort(result, elem) - pop() - los = result[-1] + if cmp_lt(elem, los): + insort(result, elem) + pop() + los = result[-1] return result # An alternative approach manifests the whole iterable in memory but # saves comparisons by heapifying all at once. Also, saves time @@ -240,7 +244,7 @@ while pos > startpos: parentpos = (pos - 1) >> 1 parent = heap[parentpos] - if newitem < parent: + if cmp_lt(newitem, parent): heap[pos] = parent pos = parentpos continue @@ -295,7 +299,7 @@ while childpos < endpos: # Set childpos to index of smaller child. rightpos = childpos + 1 - if rightpos < endpos and not heap[childpos] < heap[rightpos]: + if rightpos < endpos and not cmp_lt(heap[childpos], heap[rightpos]): childpos = rightpos # Move the smaller child up. heap[pos] = heap[childpos] diff --git a/Lib/test/test_heapq.py b/Lib/test/test_heapq.py --- a/Lib/test/test_heapq.py +++ b/Lib/test/test_heapq.py @@ -209,12 +209,6 @@ self.assertEqual(hsort(data, LT), target) self.assertEqual(hsort(data, LE), target) - # As an early adopter, we sanity check the - # test_support.import_fresh_module utility function - def test_accelerated(self): - self.assertTrue(sys.modules['heapq'] is self.module) - self.assertFalse(hasattr(self.module.heapify, 'func_code')) - #============================================================================== @@ -316,16 +310,16 @@ def test_non_sequence(self): for f in (self.module.heapify, self.module.heappop): - self.assertRaises(TypeError, f, 10) + self.assertRaises((TypeError, AttributeError), f, 10) for f in (self.module.heappush, self.module.heapreplace, self.module.nlargest, self.module.nsmallest): - self.assertRaises(TypeError, f, 10, 10) + self.assertRaises((TypeError, AttributeError), f, 10, 10) def test_len_only(self): for f in (self.module.heapify, self.module.heappop): - self.assertRaises(TypeError, f, LenOnly()) + self.assertRaises((TypeError, AttributeError), f, LenOnly()) for f in (self.module.heappush, self.module.heapreplace): - self.assertRaises(TypeError, f, LenOnly(), 10) + self.assertRaises((TypeError, AttributeError), f, LenOnly(), 10) for f in (self.module.nlargest, self.module.nsmallest): self.assertRaises(TypeError, f, 2, LenOnly()) @@ -342,7 +336,7 @@ for f in (self.module.heapify, self.module.heappop, self.module.heappush, self.module.heapreplace, self.module.nlargest, self.module.nsmallest): - self.assertRaises(TypeError, f, 10) + self.assertRaises((TypeError, AttributeError), f, 10) def test_iterable_args(self): for f in (self.module.nlargest, self.module.nsmallest): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 13 20:20:48 2011 From: python-checkins at python.org (r.david.murray) Date: Wed, 13 Apr 2011 20:20:48 +0200 Subject: [Python-checkins] cpython (3.1): Fix wording and clarify that the IDNA codec operates on full domain names. Message-ID: http://hg.python.org/cpython/rev/bc707ca54e00 changeset: 69328:bc707ca54e00 branch: 3.1 parent: 69323:bbed01a7d0d1 user: R David Murray date: Wed Apr 13 14:12:18 2011 -0400 summary: Fix wording and clarify that the IDNA codec operates on full domain names. Before reading the code to check, I wasn't sure if it operated on full domain names or just individual labels. files: Doc/library/codecs.rst | 10 ++++++++-- 1 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Doc/library/codecs.rst b/Doc/library/codecs.rst --- a/Doc/library/codecs.rst +++ b/Doc/library/codecs.rst @@ -1185,8 +1185,12 @@ IDNA on the wire, and convert back ACE labels to Unicode before presenting them to the user. -Python supports this conversion in several ways: The ``idna`` codec allows to -convert between Unicode and the ACE. Furthermore, the :mod:`socket` module +Python supports this conversion in several ways: the ``idna`` codec performs +conversion between Unicode and ACE, separating an input string into labels +based on the separator characters defined in `section 3.1`_ (1) of :rfc:`3490` +and converting each label to ACE as required, and conversely separating an input +byte string into labels based on the ``.`` separator and converting any ACE +labels found into unicode. Furthermore, the :mod:`socket` module transparently converts Unicode host names to ACE, so that applications need not be concerned about converting host names themselves when they pass them to the socket module. On top of that, modules that have host names as function @@ -1194,6 +1198,8 @@ names (:mod:`http.client` then also transparently sends an IDNA hostname in the :mailheader:`Host` field if it sends that field at all). +.. _section 3.1: http://tools.ietf.org/html/rfc3490#section-3.1 + When receiving host names from the wire (such as in reverse name lookup), no automatic conversion to Unicode is performed: Applications wishing to present such host names to the user should decode them to Unicode. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 13 20:20:48 2011 From: python-checkins at python.org (r.david.murray) Date: Wed, 13 Apr 2011 20:20:48 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): Merge: Fix wording and clarify that the IDNA codec operates on full domain Message-ID: http://hg.python.org/cpython/rev/f5672fbc7727 changeset: 69329:f5672fbc7727 branch: 3.2 parent: 69324:0eaa8b38e18b parent: 69328:bc707ca54e00 user: R David Murray date: Wed Apr 13 14:12:59 2011 -0400 summary: Merge: Fix wording and clarify that the IDNA codec operates on full domain names. Before reading the code to check, I wasn't sure if it operated on full domain names or just individual labels. files: Doc/library/codecs.rst | 10 ++++++++-- 1 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Doc/library/codecs.rst b/Doc/library/codecs.rst --- a/Doc/library/codecs.rst +++ b/Doc/library/codecs.rst @@ -1227,8 +1227,12 @@ IDNA on the wire, and convert back ACE labels to Unicode before presenting them to the user. -Python supports this conversion in several ways: The ``idna`` codec allows to -convert between Unicode and the ACE. Furthermore, the :mod:`socket` module +Python supports this conversion in several ways: the ``idna`` codec performs +conversion between Unicode and ACE, separating an input string into labels +based on the separator characters defined in `section 3.1`_ (1) of :rfc:`3490` +and converting each label to ACE as required, and conversely separating an input +byte string into labels based on the ``.`` separator and converting any ACE +labels found into unicode. Furthermore, the :mod:`socket` module transparently converts Unicode host names to ACE, so that applications need not be concerned about converting host names themselves when they pass them to the socket module. On top of that, modules that have host names as function @@ -1236,6 +1240,8 @@ names (:mod:`http.client` then also transparently sends an IDNA hostname in the :mailheader:`Host` field if it sends that field at all). +.. _section 3.1: http://tools.ietf.org/html/rfc3490#section-3.1 + When receiving host names from the wire (such as in reverse name lookup), no automatic conversion to Unicode is performed: Applications wishing to present such host names to the user should decode them to Unicode. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 13 20:20:49 2011 From: python-checkins at python.org (r.david.murray) Date: Wed, 13 Apr 2011 20:20:49 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge: Fix wording and clarify that the IDNA codec operates on full domain Message-ID: http://hg.python.org/cpython/rev/010c4abdb5fc changeset: 69330:010c4abdb5fc parent: 69326:9bc342724319 parent: 69329:f5672fbc7727 user: R David Murray date: Wed Apr 13 14:13:52 2011 -0400 summary: Merge: Fix wording and clarify that the IDNA codec operates on full domain names. Before reading the code to check, I wasn't sure if it operated on full domain names or just individual labels. files: Doc/library/codecs.rst | 10 ++++++++-- 1 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Doc/library/codecs.rst b/Doc/library/codecs.rst --- a/Doc/library/codecs.rst +++ b/Doc/library/codecs.rst @@ -1236,8 +1236,12 @@ IDNA on the wire, and convert back ACE labels to Unicode before presenting them to the user. -Python supports this conversion in several ways: The ``idna`` codec allows to -convert between Unicode and the ACE. Furthermore, the :mod:`socket` module +Python supports this conversion in several ways: the ``idna`` codec performs +conversion between Unicode and ACE, separating an input string into labels +based on the separator characters defined in `section 3.1`_ (1) of :rfc:`3490` +and converting each label to ACE as required, and conversely separating an input +byte string into labels based on the ``.`` separator and converting any ACE +labels found into unicode. Furthermore, the :mod:`socket` module transparently converts Unicode host names to ACE, so that applications need not be concerned about converting host names themselves when they pass them to the socket module. On top of that, modules that have host names as function @@ -1245,6 +1249,8 @@ names (:mod:`http.client` then also transparently sends an IDNA hostname in the :mailheader:`Host` field if it sends that field at all). +.. _section 3.1: http://tools.ietf.org/html/rfc3490#section-3.1 + When receiving host names from the wire (such as in reverse name lookup), no automatic conversion to Unicode is performed: Applications wishing to present such host names to the user should decode them to Unicode. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 13 20:20:58 2011 From: python-checkins at python.org (r.david.murray) Date: Wed, 13 Apr 2011 20:20:58 +0200 Subject: [Python-checkins] cpython (2.7): Transplant: Fix wording and clarify that the IDNA codec operates on full domain Message-ID: http://hg.python.org/cpython/rev/00d6e594a40e changeset: 69331:00d6e594a40e branch: 2.7 parent: 69327:103a2eb61069 user: R David Murray date: Wed Apr 13 14:20:30 2011 -0400 summary: Transplant: Fix wording and clarify that the IDNA codec operates on full domain names. Before reading the code to check, I wasn't sure if it operated on full domain names or just individual labels. files: Doc/library/codecs.rst | 10 ++++++++-- 1 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Doc/library/codecs.rst b/Doc/library/codecs.rst --- a/Doc/library/codecs.rst +++ b/Doc/library/codecs.rst @@ -1201,8 +1201,12 @@ IDNA on the wire, and convert back ACE labels to Unicode before presenting them to the user. -Python supports this conversion in several ways: The ``idna`` codec allows to -convert between Unicode and the ACE. Furthermore, the :mod:`socket` module +Python supports this conversion in several ways: the ``idna`` codec performs +conversion between Unicode and ACE, separating an input string into labels +based on the separator characters defined in `section 3.1`_ (1) of :rfc:`3490` +and converting each label to ACE as required, and conversely separating an input +byte string into labels based on the ``.`` separator and converting any ACE +labels found into unicode. Furthermore, the :mod:`socket` module transparently converts Unicode host names to ACE, so that applications need not be concerned about converting host names themselves when they pass them to the socket module. On top of that, modules that have host names as function @@ -1210,6 +1214,8 @@ (:mod:`httplib` then also transparently sends an IDNA hostname in the :mailheader:`Host` field if it sends that field at all). +.. _section 3.1: http://tools.ietf.org/html/rfc3490#section-3.1 + When receiving host names from the wire (such as in reverse name lookup), no automatic conversion to Unicode is performed: Applications wishing to present such host names to the user should decode them to Unicode. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 13 20:51:05 2011 From: python-checkins at python.org (raymond.hettinger) Date: Wed, 13 Apr 2011 20:51:05 +0200 Subject: [Python-checkins] cpython (3.2): Issue 3051: make pure python code pass the same tests as the C version. Message-ID: http://hg.python.org/cpython/rev/83e4765ec4cb changeset: 69332:83e4765ec4cb branch: 3.2 parent: 69329:f5672fbc7727 user: Raymond Hettinger date: Wed Apr 13 11:49:57 2011 -0700 summary: Issue 3051: make pure python code pass the same tests as the C version. files: Lib/heapq.py | 9 ++++----- Lib/test/test_heapq.py | 16 +++++----------- 2 files changed, 9 insertions(+), 16 deletions(-) diff --git a/Lib/heapq.py b/Lib/heapq.py --- a/Lib/heapq.py +++ b/Lib/heapq.py @@ -212,11 +212,10 @@ pop = result.pop los = result[-1] # los --> Largest of the nsmallest for elem in it: - if los <= elem: - continue - insort(result, elem) - pop() - los = result[-1] + if elem < los: + insort(result, elem) + pop() + los = result[-1] return result # An alternative approach manifests the whole iterable in memory but # saves comparisons by heapifying all at once. Also, saves time diff --git a/Lib/test/test_heapq.py b/Lib/test/test_heapq.py --- a/Lib/test/test_heapq.py +++ b/Lib/test/test_heapq.py @@ -211,12 +211,6 @@ self.assertEqual(hsort(data, LT), target) self.assertRaises(TypeError, data, LE) - # As an early adopter, we sanity check the - # test.support.import_fresh_module utility function - def test_accelerated(self): - self.assertTrue(sys.modules['heapq'] is self.module) - self.assertFalse(hasattr(self.module.heapify, '__code__')) - #============================================================================== @@ -319,16 +313,16 @@ def test_non_sequence(self): for f in (self.module.heapify, self.module.heappop): - self.assertRaises(TypeError, f, 10) + self.assertRaises((TypeError, AttributeError), f, 10) for f in (self.module.heappush, self.module.heapreplace, self.module.nlargest, self.module.nsmallest): - self.assertRaises(TypeError, f, 10, 10) + self.assertRaises((TypeError, AttributeError), f, 10, 10) def test_len_only(self): for f in (self.module.heapify, self.module.heappop): - self.assertRaises(TypeError, f, LenOnly()) + self.assertRaises((TypeError, AttributeError), f, LenOnly()) for f in (self.module.heappush, self.module.heapreplace): - self.assertRaises(TypeError, f, LenOnly(), 10) + self.assertRaises((TypeError, AttributeError), f, LenOnly(), 10) for f in (self.module.nlargest, self.module.nsmallest): self.assertRaises(TypeError, f, 2, LenOnly()) @@ -353,7 +347,7 @@ for f in (self.module.heapify, self.module.heappop, self.module.heappush, self.module.heapreplace, self.module.nlargest, self.module.nsmallest): - self.assertRaises(TypeError, f, 10) + self.assertRaises((TypeError, AttributeError), f, 10) def test_iterable_args(self): for f in (self.module.nlargest, self.module.nsmallest): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 13 20:51:05 2011 From: python-checkins at python.org (raymond.hettinger) Date: Wed, 13 Apr 2011 20:51:05 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): merge Message-ID: http://hg.python.org/cpython/rev/fafc84b45a9e changeset: 69333:fafc84b45a9e parent: 69330:010c4abdb5fc parent: 69332:83e4765ec4cb user: Raymond Hettinger date: Wed Apr 13 11:50:34 2011 -0700 summary: merge files: Lib/heapq.py | 9 ++++----- Lib/test/test_heapq.py | 16 +++++----------- 2 files changed, 9 insertions(+), 16 deletions(-) diff --git a/Lib/heapq.py b/Lib/heapq.py --- a/Lib/heapq.py +++ b/Lib/heapq.py @@ -212,11 +212,10 @@ pop = result.pop los = result[-1] # los --> Largest of the nsmallest for elem in it: - if los <= elem: - continue - insort(result, elem) - pop() - los = result[-1] + if elem < los: + insort(result, elem) + pop() + los = result[-1] return result # An alternative approach manifests the whole iterable in memory but # saves comparisons by heapifying all at once. Also, saves time diff --git a/Lib/test/test_heapq.py b/Lib/test/test_heapq.py --- a/Lib/test/test_heapq.py +++ b/Lib/test/test_heapq.py @@ -211,12 +211,6 @@ self.assertEqual(hsort(data, LT), target) self.assertRaises(TypeError, data, LE) - # As an early adopter, we sanity check the - # test.support.import_fresh_module utility function - def test_accelerated(self): - self.assertTrue(sys.modules['heapq'] is self.module) - self.assertFalse(hasattr(self.module.heapify, '__code__')) - #============================================================================== @@ -319,16 +313,16 @@ def test_non_sequence(self): for f in (self.module.heapify, self.module.heappop): - self.assertRaises(TypeError, f, 10) + self.assertRaises((TypeError, AttributeError), f, 10) for f in (self.module.heappush, self.module.heapreplace, self.module.nlargest, self.module.nsmallest): - self.assertRaises(TypeError, f, 10, 10) + self.assertRaises((TypeError, AttributeError), f, 10, 10) def test_len_only(self): for f in (self.module.heapify, self.module.heappop): - self.assertRaises(TypeError, f, LenOnly()) + self.assertRaises((TypeError, AttributeError), f, LenOnly()) for f in (self.module.heappush, self.module.heapreplace): - self.assertRaises(TypeError, f, LenOnly(), 10) + self.assertRaises((TypeError, AttributeError), f, LenOnly(), 10) for f in (self.module.nlargest, self.module.nsmallest): self.assertRaises(TypeError, f, 2, LenOnly()) @@ -353,7 +347,7 @@ for f in (self.module.heapify, self.module.heappop, self.module.heappush, self.module.heapreplace, self.module.nlargest, self.module.nsmallest): - self.assertRaises(TypeError, f, 10) + self.assertRaises((TypeError, AttributeError), f, 10) def test_iterable_args(self): for f in (self.module.nlargest, self.module.nsmallest): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 13 21:21:27 2011 From: python-checkins at python.org (barry.warsaw) Date: Wed, 13 Apr 2011 21:21:27 +0200 Subject: [Python-checkins] peps: Updates based on python-dev feedback. Message-ID: http://hg.python.org/peps/rev/ed1008f29bf8 changeset: 3867:ed1008f29bf8 user: Barry Warsaw date: Wed Apr 13 15:21:13 2011 -0400 summary: Updates based on python-dev feedback. * Remove the __version_info__ tuple discussion. Because of the sorting order for the non-numeric sections, this can't really work. * Remove the regexp code sample; it was distracting and ultimately isn't the core of this PEP. files: pep-0396.txt | 38 +++++++++++--------------------------- 1 files changed, 11 insertions(+), 27 deletions(-) diff --git a/pep-0396.txt b/pep-0396.txt --- a/pep-0396.txt +++ b/pep-0396.txt @@ -76,7 +76,7 @@ of an ``__version__`` module attribute by independent module developers dates back to 1995. -Another example of version information is the sqlite3 [5]_ library +Another example of version information is the sqlite3 [5]_ module with its ``sqlite_version_info``, ``version``, and ``version_info`` attributes. It may not be immediately obvious which attribute contains a version number for the module, and which contains a version @@ -121,13 +121,6 @@ supplied revision numbers, or any other semantically different version numbers (e.g. underlying library version number). -#. Wherever a ``__version__`` attribute exists, a module MAY also - include a ``__version_info__`` attribute, containing a tuple - representation of the module version number, for easy comparisons. - -#. ``__version_info__`` SHOULD be of the format returned by PEP 386's - ``parse_version()`` function. - #. The ``version`` attribute in a classic distutils ``setup.py`` file, or the PEP 345 [7]_ ``Version`` metadata field SHOULD be derived from the ``__version__`` field, or vice versa. @@ -184,8 +177,11 @@ number once, and have all the other uses derive from this single definition. -While there are any number of ways this could be done, this section -describes one possible approach, for each scenario. +This could be done in any number of ways, a few of which are outlined +below. These are included for illustrative purposes only and are not +intended to be definitive, complete, or all-encompassing. Other +approaches are possible, and some included below may have limitations +that prevent their use in some situations. Let's say Elle adds this attribute to her module file ``elle.py``:: @@ -208,24 +204,12 @@ the ``elle`` module has been converted). In that case, it's not much more difficult to write a little code to -parse the ``__version__`` from the file rather than importing it:: +parse the ``__version__`` from the file rather than importing it. +Without providing too much detail, it's likely that modules such as +``distutils2`` will provide a way to parse version strings from files. +E.g.:: - import re - DEFAULT_VERSION_RE = re.compile(r'(?P\d+\.\d(?:\.\d+)?)') - - def get_version(filename, pattern=None): - if pattern is None: - cre = DEFAULT_VERSION_RE - else: - cre = re.compile(pattern) - with open(filename) as fp: - for line in fp: - if line.startswith('__version__'): - mo = cre.search(line) - assert mo, 'No valid __version__ string found' - return mo.group('version') - raise AssertionError('No __version__ assignment found') - + from distutils2 import get_version setup(name='elle', version=get_version('elle.py')) -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Wed Apr 13 22:46:37 2011 From: python-checkins at python.org (r.david.murray) Date: Wed, 13 Apr 2011 22:46:37 +0200 Subject: [Python-checkins] cpython: #11684: Complete parser bytes interface by adding BytesHeaderParser Message-ID: http://hg.python.org/cpython/rev/a95d936ce8eb changeset: 69334:a95d936ce8eb user: R David Murray date: Wed Apr 13 16:46:05 2011 -0400 summary: #11684: Complete parser bytes interface by adding BytesHeaderParser Patch by Steffen Daode Nurpmeso. files: Doc/library/email.parser.rst | 14 ++++++---- Lib/email/generator.py | 4 ++- Lib/email/parser.py | 10 +++++++- Lib/test/test_email/test_email.py | 24 +++++++++++++++++++ Misc/NEWS | 2 + 5 files changed, 46 insertions(+), 8 deletions(-) diff --git a/Doc/library/email.parser.rst b/Doc/library/email.parser.rst --- a/Doc/library/email.parser.rst +++ b/Doc/library/email.parser.rst @@ -94,12 +94,14 @@ The :class:`Parser` class, imported from the :mod:`email.parser` module, provides an API that can be used to parse a message when the complete contents of the message are available in a string or file. The :mod:`email.parser` -module also provides a second class, called :class:`HeaderParser` which can be -used if you're only interested in the headers of the message. -:class:`HeaderParser` can be much faster in these situations, since it does not -attempt to parse the message body, instead setting the payload to the raw body -as a string. :class:`HeaderParser` has the same API as the :class:`Parser` -class. +module also provides header-only parsers, called :class:`HeaderParser` and +:class:`BytesHeaderParser`, which can be used if you're only interested in the +headers of the message. :class:`HeaderParser` and :class:`BytesHeaderParser` +can be much faster in these situations, since they do not attempt to parse the +message body, instead setting the payload to the raw body as a string. They +have the same API as the :class:`Parser` and :class:`BytesParser` classes. + +.. versionadded:: 3.3 BytesHeaderParser .. class:: Parser(_class=email.message.Message) diff --git a/Lib/email/generator.py b/Lib/email/generator.py --- a/Lib/email/generator.py +++ b/Lib/email/generator.py @@ -297,10 +297,12 @@ # message/rfc822. Such messages are generated by, for example, # Groupwise when forwarding unadorned messages. (Issue 7970.) So # in that case we just emit the string body. - payload = msg.get_payload() + payload = msg._payload if isinstance(payload, list): g.flatten(msg.get_payload(0), unixfrom=False, linesep=self._NL) payload = s.getvalue() + else: + payload = self._encode(payload) self._fp.write(payload) # This used to be a module level function; we use a classmethod for this diff --git a/Lib/email/parser.py b/Lib/email/parser.py --- a/Lib/email/parser.py +++ b/Lib/email/parser.py @@ -4,7 +4,7 @@ """A parser of RFC 2822 and MIME email messages.""" -__all__ = ['Parser', 'HeaderParser'] +__all__ = ['Parser', 'HeaderParser', 'BytesParser', 'BytesHeaderParser'] import warnings from io import StringIO, TextIOWrapper @@ -114,3 +114,11 @@ """ text = text.decode('ASCII', errors='surrogateescape') return self.parser.parsestr(text, headersonly) + + +class BytesHeaderParser(BytesParser): + def parse(self, fp, headersonly=True): + return BytesParser.parse(self, fp, headersonly=True) + + def parsebytes(self, text, headersonly=True): + return BytesParser.parsebytes(self, text, headersonly=True) diff --git a/Lib/test/test_email/test_email.py b/Lib/test/test_email/test_email.py --- a/Lib/test/test_email/test_email.py +++ b/Lib/test/test_email/test_email.py @@ -177,6 +177,17 @@ gen.flatten(msg, False) self.assertEqual(out.getvalue(), msgdata) + def test_byte_message_rfc822_only(self): + # Make sure new bytes header parser also passes this. + with openfile('msg_46.txt', 'rb') as fp: + msgdata = fp.read() + parser = email.parser.BytesHeaderParser() + msg = parser.parsebytes(msgdata) + out = BytesIO() + gen = email.generator.BytesGenerator(out) + gen.flatten(msg) + self.assertEqual(out.getvalue(), msgdata) + def test_get_decoded_payload(self): eq = self.assertEqual msg = self._msgobj('msg_10.txt') @@ -2749,6 +2760,7 @@ class TestParsers(TestEmailBase): + def test_header_parser(self): eq = self.assertEqual # Parse only the headers of a complex multipart MIME document @@ -2760,6 +2772,18 @@ self.assertFalse(msg.is_multipart()) self.assertTrue(isinstance(msg.get_payload(), str)) + def test_bytes_header_parser(self): + eq = self.assertEqual + # Parse only the headers of a complex multipart MIME document + with openfile('msg_02.txt', 'rb') as fp: + msg = email.parser.BytesHeaderParser().parse(fp) + eq(msg['from'], 'ppp-request at zzz.org') + eq(msg['to'], 'ppp at zzz.org') + eq(msg.get_content_type(), 'multipart/mixed') + self.assertFalse(msg.is_multipart()) + self.assertTrue(isinstance(msg.get_payload(), str)) + self.assertTrue(isinstance(msg.get_payload(decode=True), bytes)) + def test_whitespace_continuation(self): eq = self.assertEqual # This message contains a line after the Subject: header that has only diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -103,6 +103,8 @@ Library ------- +- Issue #11684: complete email.parser bytes API by adding BytesHeaderParser. + - The bz2 module now handles 4GiB+ input buffers correctly. - Issue #9233: Fix json.loads('{}') to return a dict (instead of a list), when -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 13 23:13:10 2011 From: python-checkins at python.org (brian.curtin) Date: Wed, 13 Apr 2011 23:13:10 +0200 Subject: [Python-checkins] cpython (3.1): Remove inexistent tools Message-ID: http://hg.python.org/cpython/rev/135cf9104f56 changeset: 69335:135cf9104f56 branch: 3.1 parent: 69328:bc707ca54e00 user: Brian Curtin date: Wed Apr 13 16:04:27 2011 -0500 summary: Remove inexistent tools files: Tools/README | 12 ------------ 1 files changed, 0 insertions(+), 12 deletions(-) diff --git a/Tools/README b/Tools/README --- a/Tools/README +++ b/Tools/README @@ -1,15 +1,6 @@ This directory contains a number of Python programs that are useful while building or extending Python. -audiopy Audiopy is a program to control the Solaris audio - device, allowing you to choose both the input and - output devices, and to set the output volume, that can - be run either as a command-line script, or as a - Tkinter application. - -compiler Tools used to maintain the compiler package in the - standard library. - faqwiz FAQ Wizard. See http://www.python.org/cgi-bin/faqw.py for a live example. @@ -34,9 +25,6 @@ unicode Tools used to generate unicode database files for Python 2.0 (by Fredrik Lundh). -versioncheck A tool to automate checking whether you have the latest - version of a package (by Jack Jansen). - webchecker A link checker for web sites. world Script to take a list of Internet addresses and print -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 13 23:13:11 2011 From: python-checkins at python.org (brian.curtin) Date: Wed, 13 Apr 2011 23:13:11 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): Merge 3.1 Message-ID: http://hg.python.org/cpython/rev/eecde4602c5c changeset: 69336:eecde4602c5c branch: 3.2 parent: 69332:83e4765ec4cb parent: 69335:135cf9104f56 user: Brian Curtin date: Wed Apr 13 16:11:37 2011 -0500 summary: Merge 3.1 files: Tools/README | 5 ----- 1 files changed, 0 insertions(+), 5 deletions(-) diff --git a/Tools/README b/Tools/README --- a/Tools/README +++ b/Tools/README @@ -40,8 +40,3 @@ unittestgui A Tkinter based GUI test runner for unittest, with test discovery. - -world Script to take a list of Internet addresses and print - out where in the world those addresses originate from, - based on the top-level domain country code found in - the address. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 13 23:13:12 2011 From: python-checkins at python.org (brian.curtin) Date: Wed, 13 Apr 2011 23:13:12 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge 3.2 Message-ID: http://hg.python.org/cpython/rev/602d317d2257 changeset: 69337:602d317d2257 parent: 69334:a95d936ce8eb parent: 69336:eecde4602c5c user: Brian Curtin date: Wed Apr 13 16:12:46 2011 -0500 summary: Merge 3.2 files: Tools/README | 5 ----- 1 files changed, 0 insertions(+), 5 deletions(-) diff --git a/Tools/README b/Tools/README --- a/Tools/README +++ b/Tools/README @@ -40,8 +40,3 @@ unittestgui A Tkinter based GUI test runner for unittest, with test discovery. - -world Script to take a list of Internet addresses and print - out where in the world those addresses originate from, - based on the top-level domain country code found in - the address. -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Thu Apr 14 05:01:25 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Thu, 14 Apr 2011 05:01:25 +0200 Subject: [Python-checkins] Daily reference leaks (602d317d2257): sum=0 Message-ID: results for 602d317d2257 on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogK8QmmC', '-x'] From python-checkins at python.org Thu Apr 14 05:54:15 2011 From: python-checkins at python.org (ezio.melotti) Date: Thu, 14 Apr 2011 05:54:15 +0200 Subject: [Python-checkins] cpython (3.1): #9101: backport json reference in configparser doc. Message-ID: http://hg.python.org/cpython/rev/d0ada1e369cd changeset: 69338:d0ada1e369cd branch: 3.1 parent: 69335:135cf9104f56 user: Ezio Melotti date: Thu Apr 14 06:41:38 2011 +0300 summary: #9101: backport json reference in configparser doc. files: Doc/library/configparser.rst | 10 ++++++++++ 1 files changed, 10 insertions(+), 0 deletions(-) diff --git a/Doc/library/configparser.rst b/Doc/library/configparser.rst --- a/Doc/library/configparser.rst +++ b/Doc/library/configparser.rst @@ -26,6 +26,16 @@ This library does *not* interpret or write the value-type prefixes used in the Windows Registry extended version of INI syntax. +.. seealso:: + + Module :mod:`shlex` + Support for a creating Unix shell-like mini-languages which can be used + as an alternate format for application configuration files. + + Module :mod:`json` + The json module implements a subset of JavaScript syntax which can also + be used for this purpose. + The configuration file consists of sections, led by a ``[section]`` header and followed by ``name: value`` entries, with continuations in the style of :rfc:`822` (see section 3.1.1, "LONG HEADER FIELDS"); ``name=value`` is also -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Apr 14 05:54:16 2011 From: python-checkins at python.org (ezio.melotti) Date: Thu, 14 Apr 2011 05:54:16 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): Dummy merge with 3.1. Message-ID: http://hg.python.org/cpython/rev/71220d86cde9 changeset: 69339:71220d86cde9 branch: 3.2 parent: 69336:eecde4602c5c parent: 69338:d0ada1e369cd user: Ezio Melotti date: Thu Apr 14 06:48:34 2011 +0300 summary: Dummy merge with 3.1. files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Apr 14 05:54:17 2011 From: python-checkins at python.org (ezio.melotti) Date: Thu, 14 Apr 2011 05:54:17 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Dummy merge with 3.2. Message-ID: http://hg.python.org/cpython/rev/1afb11436a4a changeset: 69340:1afb11436a4a parent: 69337:602d317d2257 parent: 69339:71220d86cde9 user: Ezio Melotti date: Thu Apr 14 06:49:28 2011 +0300 summary: Dummy merge with 3.2. files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Apr 14 05:54:21 2011 From: python-checkins at python.org (ezio.melotti) Date: Thu, 14 Apr 2011 05:54:21 +0200 Subject: [Python-checkins] cpython (2.7): #9101: backport json reference in configparser doc. Message-ID: http://hg.python.org/cpython/rev/5a09a335e8e7 changeset: 69341:5a09a335e8e7 branch: 2.7 parent: 69331:00d6e594a40e user: Ezio Melotti date: Thu Apr 14 06:53:44 2011 +0300 summary: #9101: backport json reference in configparser doc. files: Doc/library/configparser.rst | 10 ++++++++++ 1 files changed, 10 insertions(+), 0 deletions(-) diff --git a/Doc/library/configparser.rst b/Doc/library/configparser.rst --- a/Doc/library/configparser.rst +++ b/Doc/library/configparser.rst @@ -32,6 +32,16 @@ This library does *not* interpret or write the value-type prefixes used in the Windows Registry extended version of INI syntax. +.. seealso:: + + Module :mod:`shlex` + Support for a creating Unix shell-like mini-languages which can be used + as an alternate format for application configuration files. + + Module :mod:`json` + The json module implements a subset of JavaScript syntax which can also + be used for this purpose. + The configuration file consists of sections, led by a ``[section]`` header and followed by ``name: value`` entries, with continuations in the style of :rfc:`822` (see section 3.1.1, "LONG HEADER FIELDS"); ``name=value`` is also -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Apr 14 06:52:11 2011 From: python-checkins at python.org (ezio.melotti) Date: Thu, 14 Apr 2011 06:52:11 +0200 Subject: [Python-checkins] cpython (3.1): #11840: Improve c-api/unicode documentation. Patch by Sandro Tosi. Message-ID: http://hg.python.org/cpython/rev/11c72a305eb5 changeset: 69342:11c72a305eb5 branch: 3.1 parent: 69338:d0ada1e369cd user: Ezio Melotti date: Thu Apr 14 07:43:53 2011 +0300 summary: #11840: Improve c-api/unicode documentation. Patch by Sandro Tosi. files: Doc/c-api/unicode.rst | 56 ++++++++++++++---------------- 1 files changed, 27 insertions(+), 29 deletions(-) diff --git a/Doc/c-api/unicode.rst b/Doc/c-api/unicode.rst --- a/Doc/c-api/unicode.rst +++ b/Doc/c-api/unicode.rst @@ -329,8 +329,8 @@ incremented refcount. :class:`bytes`, :class:`bytearray` and other char buffer compatible objects - are decoded according to the given encoding and using the error handling - defined by errors. Both can be *NULL* to have the interface use the default + are decoded according to the given *encoding* and using the error handling + defined by *errors*. Both can be *NULL* to have the interface use the default values (see the next section for details). All other objects, including Unicode objects, cause a :exc:`TypeError` to be @@ -390,12 +390,12 @@ wchar_t Support """"""""""""""" -wchar_t support for platforms which support it: +:ctype:`wchar_t` support for platforms which support it: .. cfunction:: PyObject* PyUnicode_FromWideChar(const wchar_t *w, Py_ssize_t size) - Create a Unicode object from the :ctype:`wchar_t` buffer *w* of the given size. - Passing -1 as the size indicates that the function must itself compute the length, + Create a Unicode object from the :ctype:`wchar_t` buffer *w* of the given *size*. + Passing -1 as the *size* indicates that the function must itself compute the length, using wcslen. Return *NULL* on failure. @@ -419,15 +419,15 @@ Python provides a set of built-in codecs which are written in C for speed. All of these codecs are directly usable via the following functions. -Many of the following APIs take two arguments encoding and errors. These -parameters encoding and errors have the same semantics as the ones of the -built-in :func:`str` string object constructor. +Many of the following APIs take two arguments encoding and errors, and they +have the same semantics as the ones of the built-in :func:`str` string object +constructor. Setting encoding to *NULL* causes the default encoding to be used which is ASCII. The file system calls should use :cfunc:`PyUnicode_FSConverter` for encoding file names. This uses the variable :cdata:`Py_FileSystemDefaultEncoding` internally. This -variable should be treated as read-only: On some systems, it will be a +variable should be treated as read-only: on some systems, it will be a pointer to a static string, on others, it will change at run-time (such as when the application invokes setlocale). @@ -456,7 +456,7 @@ .. cfunction:: PyObject* PyUnicode_Encode(const Py_UNICODE *s, Py_ssize_t size, const char *encoding, const char *errors) - Encode the :ctype:`Py_UNICODE` buffer of the given size and return a Python + Encode the :ctype:`Py_UNICODE` buffer *s* of the given *size* and return a Python bytes object. *encoding* and *errors* have the same meaning as the parameters of the same name in the Unicode :meth:`encode` method. The codec to be used is looked up using the Python codec registry. Return *NULL* if an @@ -494,7 +494,7 @@ .. cfunction:: PyObject* PyUnicode_EncodeUTF8(const Py_UNICODE *s, Py_ssize_t size, const char *errors) - Encode the :ctype:`Py_UNICODE` buffer of the given size using UTF-8 and + Encode the :ctype:`Py_UNICODE` buffer *s* of the given *size* using UTF-8 and return a Python bytes object. Return *NULL* if an exception was raised by the codec. @@ -514,7 +514,7 @@ .. cfunction:: PyObject* PyUnicode_DecodeUTF32(const char *s, Py_ssize_t size, const char *errors, int *byteorder) - Decode *length* bytes from a UTF-32 encoded buffer string and return the + Decode *size* bytes from a UTF-32 encoded buffer string and return the corresponding Unicode object. *errors* (if non-*NULL*) defines the error handling. It defaults to "strict". @@ -582,7 +582,7 @@ .. cfunction:: PyObject* PyUnicode_DecodeUTF16(const char *s, Py_ssize_t size, const char *errors, int *byteorder) - Decode *length* bytes from a UTF-16 encoded buffer string and return the + Decode *size* bytes from a UTF-16 encoded buffer string and return the corresponding Unicode object. *errors* (if non-*NULL*) defines the error handling. It defaults to "strict". @@ -714,7 +714,7 @@ .. cfunction:: PyObject* PyUnicode_EncodeRawUnicodeEscape(const Py_UNICODE *s, Py_ssize_t size, const char *errors) - Encode the :ctype:`Py_UNICODE` buffer of the given size using Raw-Unicode-Escape + Encode the :ctype:`Py_UNICODE` buffer of the given *size* using Raw-Unicode-Escape and return a Python string object. Return *NULL* if an exception was raised by the codec. @@ -741,7 +741,7 @@ .. cfunction:: PyObject* PyUnicode_EncodeLatin1(const Py_UNICODE *s, Py_ssize_t size, const char *errors) - Encode the :ctype:`Py_UNICODE` buffer of the given size using Latin-1 and + Encode the :ctype:`Py_UNICODE` buffer of the given *size* using Latin-1 and return a Python bytes object. Return *NULL* if an exception was raised by the codec. @@ -768,7 +768,7 @@ .. cfunction:: PyObject* PyUnicode_EncodeASCII(const Py_UNICODE *s, Py_ssize_t size, const char *errors) - Encode the :ctype:`Py_UNICODE` buffer of the given size using ASCII and + Encode the :ctype:`Py_UNICODE` buffer of the given *size* using ASCII and return a Python bytes object. Return *NULL* if an exception was raised by the codec. @@ -783,8 +783,6 @@ Character Map Codecs """""""""""""""""""" -These are the mapping codec APIs: - This codec is special in that it can be used to implement many different codecs (and this is in fact what was done to obtain most of the standard codecs included in the :mod:`encodings` package). The codec uses mapping to encode and @@ -806,6 +804,7 @@ resp. Because of this, mappings only need to contain those mappings which map characters to different code points. +These are the mapping codec APIs: .. cfunction:: PyObject* PyUnicode_DecodeCharmap(const char *s, Py_ssize_t size, PyObject *mapping, const char *errors) @@ -819,7 +818,7 @@ .. cfunction:: PyObject* PyUnicode_EncodeCharmap(const Py_UNICODE *s, Py_ssize_t size, PyObject *mapping, const char *errors) - Encode the :ctype:`Py_UNICODE` buffer of the given size using the given + Encode the :ctype:`Py_UNICODE` buffer of the given *size* using the given *mapping* object and return a Python string object. Return *NULL* if an exception was raised by the codec. @@ -835,7 +834,7 @@ .. cfunction:: PyObject* PyUnicode_TranslateCharmap(const Py_UNICODE *s, Py_ssize_t size, PyObject *table, const char *errors) - Translate a :ctype:`Py_UNICODE` buffer of the given length by applying a + Translate a :ctype:`Py_UNICODE` buffer of the given *size* by applying a character mapping *table* to it and return the resulting Unicode object. Return *NULL* when an exception was raised by the codec. @@ -847,16 +846,15 @@ :exc:`LookupError`) are left untouched and are copied as-is. +MBCS codecs for Windows +""""""""""""""""""""""" + These are the MBCS codec APIs. They are currently only available on Windows and use the Win32 MBCS converters to implement the conversions. Note that MBCS (or DBCS) is a class of encodings, not just one. The target encoding is defined by the user settings on the machine running the codec. -MBCS codecs for Windows -""""""""""""""""""""""" - - .. cfunction:: PyObject* PyUnicode_DecodeMBCS(const char *s, Py_ssize_t size, const char *errors) Create a Unicode object by decoding *size* bytes of the MBCS encoded string *s*. @@ -873,7 +871,7 @@ .. cfunction:: PyObject* PyUnicode_EncodeMBCS(const Py_UNICODE *s, Py_ssize_t size, const char *errors) - Encode the :ctype:`Py_UNICODE` buffer of the given size using MBCS and return + Encode the :ctype:`Py_UNICODE` buffer of the given *size* using MBCS and return a Python bytes object. Return *NULL* if an exception was raised by the codec. @@ -908,7 +906,7 @@ .. cfunction:: PyObject* PyUnicode_Split(PyObject *s, PyObject *sep, Py_ssize_t maxsplit) - Split a string giving a list of Unicode strings. If sep is *NULL*, splitting + Split a string giving a list of Unicode strings. If *sep* is *NULL*, splitting will be done at all whitespace substrings. Otherwise, splits occur at the given separator. At most *maxsplit* splits will be done. If negative, no limit is set. Separators are not included in the resulting list. @@ -939,20 +937,20 @@ .. cfunction:: PyObject* PyUnicode_Join(PyObject *separator, PyObject *seq) - Join a sequence of strings using the given separator and return the resulting + Join a sequence of strings using the given *separator* and return the resulting Unicode string. .. cfunction:: int PyUnicode_Tailmatch(PyObject *str, PyObject *substr, Py_ssize_t start, Py_ssize_t end, int direction) - Return 1 if *substr* matches *str*[*start*:*end*] at the given tail end + Return 1 if *substr* matches ``str[start:end]`` at the given tail end (*direction* == -1 means to do a prefix match, *direction* == 1 a suffix match), 0 otherwise. Return ``-1`` if an error occurred. .. cfunction:: Py_ssize_t PyUnicode_Find(PyObject *str, PyObject *substr, Py_ssize_t start, Py_ssize_t end, int direction) - Return the first position of *substr* in *str*[*start*:*end*] using the given + Return the first position of *substr* in ``str[start:end]`` using the given *direction* (*direction* == 1 means to do a forward search, *direction* == -1 a backward search). The return value is the index of the first match; a value of ``-1`` indicates that no match was found, and ``-2`` indicates that an error -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Apr 14 06:52:12 2011 From: python-checkins at python.org (ezio.melotti) Date: Thu, 14 Apr 2011 06:52:12 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): #11840: Merge with 3.1. Message-ID: http://hg.python.org/cpython/rev/62679f2ca9e5 changeset: 69343:62679f2ca9e5 branch: 3.2 parent: 69339:71220d86cde9 parent: 69342:11c72a305eb5 user: Ezio Melotti date: Thu Apr 14 07:50:25 2011 +0300 summary: #11840: Merge with 3.1. files: Doc/c-api/unicode.rst | 64 +++++++++++++++--------------- 1 files changed, 31 insertions(+), 33 deletions(-) diff --git a/Doc/c-api/unicode.rst b/Doc/c-api/unicode.rst --- a/Doc/c-api/unicode.rst +++ b/Doc/c-api/unicode.rst @@ -331,7 +331,7 @@ .. c:function:: PyObject* PyUnicode_TransformDecimalToASCII(Py_UNICODE *s, Py_ssize_t size) Create a Unicode object by replacing all decimal digits in - :c:type:`Py_UNICODE` buffer of the given size by ASCII digits 0--9 + :c:type:`Py_UNICODE` buffer of the given *size* by ASCII digits 0--9 according to their decimal value. Return *NULL* if an exception occurs. @@ -344,7 +344,7 @@ .. c:function:: Py_UNICODE* PyUnicode_AsUnicodeCopy(PyObject *unicode) - Create a copy of a unicode string ending with a nul character. Return *NULL* + Create a copy of a Unicode string ending with a nul character. Return *NULL* and raise a :exc:`MemoryError` exception on memory allocation failure, otherwise return a new allocated buffer (use :c:func:`PyMem_Free` to free the buffer). @@ -363,8 +363,8 @@ incremented refcount. :class:`bytes`, :class:`bytearray` and other char buffer compatible objects - are decoded according to the given encoding and using the error handling - defined by errors. Both can be *NULL* to have the interface use the default + are decoded according to the given *encoding* and using the error handling + defined by *errors*. Both can be *NULL* to have the interface use the default values (see the next section for details). All other objects, including Unicode objects, cause a :exc:`TypeError` to be @@ -458,12 +458,12 @@ wchar_t Support """"""""""""""" -wchar_t support for platforms which support it: +:c:type:`wchar_t` support for platforms which support it: .. c:function:: PyObject* PyUnicode_FromWideChar(const wchar_t *w, Py_ssize_t size) - Create a Unicode object from the :c:type:`wchar_t` buffer *w* of the given size. - Passing -1 as the size indicates that the function must itself compute the length, + Create a Unicode object from the :c:type:`wchar_t` buffer *w* of the given *size*. + Passing -1 as the *size* indicates that the function must itself compute the length, using wcslen. Return *NULL* on failure. @@ -501,15 +501,15 @@ Python provides a set of built-in codecs which are written in C for speed. All of these codecs are directly usable via the following functions. -Many of the following APIs take two arguments encoding and errors. These -parameters encoding and errors have the same semantics as the ones of the -built-in :func:`str` string object constructor. +Many of the following APIs take two arguments encoding and errors, and they +have the same semantics as the ones of the built-in :func:`str` string object +constructor. Setting encoding to *NULL* causes the default encoding to be used which is ASCII. The file system calls should use :c:func:`PyUnicode_FSConverter` for encoding file names. This uses the variable :c:data:`Py_FileSystemDefaultEncoding` internally. This -variable should be treated as read-only: On some systems, it will be a +variable should be treated as read-only: on some systems, it will be a pointer to a static string, on others, it will change at run-time (such as when the application invokes setlocale). @@ -538,7 +538,7 @@ .. c:function:: PyObject* PyUnicode_Encode(const Py_UNICODE *s, Py_ssize_t size, const char *encoding, const char *errors) - Encode the :c:type:`Py_UNICODE` buffer of the given size and return a Python + Encode the :c:type:`Py_UNICODE` buffer *s* of the given *size* and return a Python bytes object. *encoding* and *errors* have the same meaning as the parameters of the same name in the Unicode :meth:`encode` method. The codec to be used is looked up using the Python codec registry. Return *NULL* if an @@ -576,7 +576,7 @@ .. c:function:: PyObject* PyUnicode_EncodeUTF8(const Py_UNICODE *s, Py_ssize_t size, const char *errors) - Encode the :c:type:`Py_UNICODE` buffer of the given size using UTF-8 and + Encode the :c:type:`Py_UNICODE` buffer *s* of the given *size* using UTF-8 and return a Python bytes object. Return *NULL* if an exception was raised by the codec. @@ -596,7 +596,7 @@ .. c:function:: PyObject* PyUnicode_DecodeUTF32(const char *s, Py_ssize_t size, const char *errors, int *byteorder) - Decode *length* bytes from a UTF-32 encoded buffer string and return the + Decode *size* bytes from a UTF-32 encoded buffer string and return the corresponding Unicode object. *errors* (if non-*NULL*) defines the error handling. It defaults to "strict". @@ -664,7 +664,7 @@ .. c:function:: PyObject* PyUnicode_DecodeUTF16(const char *s, Py_ssize_t size, const char *errors, int *byteorder) - Decode *length* bytes from a UTF-16 encoded buffer string and return the + Decode *size* bytes from a UTF-16 encoded buffer string and return the corresponding Unicode object. *errors* (if non-*NULL*) defines the error handling. It defaults to "strict". @@ -770,7 +770,7 @@ .. c:function:: PyObject* PyUnicode_EncodeUnicodeEscape(const Py_UNICODE *s, Py_ssize_t size) - Encode the :c:type:`Py_UNICODE` buffer of the given size using Unicode-Escape and + Encode the :c:type:`Py_UNICODE` buffer of the given *size* using Unicode-Escape and return a Python string object. Return *NULL* if an exception was raised by the codec. @@ -796,7 +796,7 @@ .. c:function:: PyObject* PyUnicode_EncodeRawUnicodeEscape(const Py_UNICODE *s, Py_ssize_t size, const char *errors) - Encode the :c:type:`Py_UNICODE` buffer of the given size using Raw-Unicode-Escape + Encode the :c:type:`Py_UNICODE` buffer of the given *size* using Raw-Unicode-Escape and return a Python string object. Return *NULL* if an exception was raised by the codec. @@ -823,7 +823,7 @@ .. c:function:: PyObject* PyUnicode_EncodeLatin1(const Py_UNICODE *s, Py_ssize_t size, const char *errors) - Encode the :c:type:`Py_UNICODE` buffer of the given size using Latin-1 and + Encode the :c:type:`Py_UNICODE` buffer of the given *size* using Latin-1 and return a Python bytes object. Return *NULL* if an exception was raised by the codec. @@ -850,7 +850,7 @@ .. c:function:: PyObject* PyUnicode_EncodeASCII(const Py_UNICODE *s, Py_ssize_t size, const char *errors) - Encode the :c:type:`Py_UNICODE` buffer of the given size using ASCII and + Encode the :c:type:`Py_UNICODE` buffer of the given *size* using ASCII and return a Python bytes object. Return *NULL* if an exception was raised by the codec. @@ -865,8 +865,6 @@ Character Map Codecs """""""""""""""""""" -These are the mapping codec APIs: - This codec is special in that it can be used to implement many different codecs (and this is in fact what was done to obtain most of the standard codecs included in the :mod:`encodings` package). The codec uses mapping to encode and @@ -888,6 +886,7 @@ resp. Because of this, mappings only need to contain those mappings which map characters to different code points. +These are the mapping codec APIs: .. c:function:: PyObject* PyUnicode_DecodeCharmap(const char *s, Py_ssize_t size, PyObject *mapping, const char *errors) @@ -901,7 +900,7 @@ .. c:function:: PyObject* PyUnicode_EncodeCharmap(const Py_UNICODE *s, Py_ssize_t size, PyObject *mapping, const char *errors) - Encode the :c:type:`Py_UNICODE` buffer of the given size using the given + Encode the :c:type:`Py_UNICODE` buffer of the given *size* using the given *mapping* object and return a Python string object. Return *NULL* if an exception was raised by the codec. @@ -917,7 +916,7 @@ .. c:function:: PyObject* PyUnicode_TranslateCharmap(const Py_UNICODE *s, Py_ssize_t size, PyObject *table, const char *errors) - Translate a :c:type:`Py_UNICODE` buffer of the given length by applying a + Translate a :c:type:`Py_UNICODE` buffer of the given *size* by applying a character mapping *table* to it and return the resulting Unicode object. Return *NULL* when an exception was raised by the codec. @@ -929,16 +928,15 @@ :exc:`LookupError`) are left untouched and are copied as-is. + +MBCS codecs for Windows +""""""""""""""""""""""" + These are the MBCS codec APIs. They are currently only available on Windows and use the Win32 MBCS converters to implement the conversions. Note that MBCS (or DBCS) is a class of encodings, not just one. The target encoding is defined by the user settings on the machine running the codec. - -MBCS codecs for Windows -""""""""""""""""""""""" - - .. c:function:: PyObject* PyUnicode_DecodeMBCS(const char *s, Py_ssize_t size, const char *errors) Create a Unicode object by decoding *size* bytes of the MBCS encoded string *s*. @@ -955,7 +953,7 @@ .. c:function:: PyObject* PyUnicode_EncodeMBCS(const Py_UNICODE *s, Py_ssize_t size, const char *errors) - Encode the :c:type:`Py_UNICODE` buffer of the given size using MBCS and return + Encode the :c:type:`Py_UNICODE` buffer of the given *size* using MBCS and return a Python bytes object. Return *NULL* if an exception was raised by the codec. @@ -990,7 +988,7 @@ .. c:function:: PyObject* PyUnicode_Split(PyObject *s, PyObject *sep, Py_ssize_t maxsplit) - Split a string giving a list of Unicode strings. If sep is *NULL*, splitting + Split a string giving a list of Unicode strings. If *sep* is *NULL*, splitting will be done at all whitespace substrings. Otherwise, splits occur at the given separator. At most *maxsplit* splits will be done. If negative, no limit is set. Separators are not included in the resulting list. @@ -1021,20 +1019,20 @@ .. c:function:: PyObject* PyUnicode_Join(PyObject *separator, PyObject *seq) - Join a sequence of strings using the given separator and return the resulting + Join a sequence of strings using the given *separator* and return the resulting Unicode string. .. c:function:: int PyUnicode_Tailmatch(PyObject *str, PyObject *substr, Py_ssize_t start, Py_ssize_t end, int direction) - Return 1 if *substr* matches *str*[*start*:*end*] at the given tail end + Return 1 if *substr* matches ``str[start:end]`` at the given tail end (*direction* == -1 means to do a prefix match, *direction* == 1 a suffix match), 0 otherwise. Return ``-1`` if an error occurred. .. c:function:: Py_ssize_t PyUnicode_Find(PyObject *str, PyObject *substr, Py_ssize_t start, Py_ssize_t end, int direction) - Return the first position of *substr* in *str*[*start*:*end*] using the given + Return the first position of *substr* in ``str[start:end]`` using the given *direction* (*direction* == 1 means to do a forward search, *direction* == -1 a backward search). The return value is the index of the first match; a value of ``-1`` indicates that no match was found, and ``-2`` indicates that an error -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Apr 14 06:52:15 2011 From: python-checkins at python.org (ezio.melotti) Date: Thu, 14 Apr 2011 06:52:15 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): #11840: Merge with 3.2. Message-ID: http://hg.python.org/cpython/rev/1f767f834e67 changeset: 69344:1f767f834e67 parent: 69340:1afb11436a4a parent: 69343:62679f2ca9e5 user: Ezio Melotti date: Thu Apr 14 07:51:57 2011 +0300 summary: #11840: Merge with 3.2. files: Doc/c-api/unicode.rst | 64 +++++++++++++++--------------- 1 files changed, 31 insertions(+), 33 deletions(-) diff --git a/Doc/c-api/unicode.rst b/Doc/c-api/unicode.rst --- a/Doc/c-api/unicode.rst +++ b/Doc/c-api/unicode.rst @@ -343,7 +343,7 @@ .. c:function:: PyObject* PyUnicode_TransformDecimalToASCII(Py_UNICODE *s, Py_ssize_t size) Create a Unicode object by replacing all decimal digits in - :c:type:`Py_UNICODE` buffer of the given size by ASCII digits 0--9 + :c:type:`Py_UNICODE` buffer of the given *size* by ASCII digits 0--9 according to their decimal value. Return *NULL* if an exception occurs. @@ -356,7 +356,7 @@ .. c:function:: Py_UNICODE* PyUnicode_AsUnicodeCopy(PyObject *unicode) - Create a copy of a unicode string ending with a nul character. Return *NULL* + Create a copy of a Unicode string ending with a nul character. Return *NULL* and raise a :exc:`MemoryError` exception on memory allocation failure, otherwise return a new allocated buffer (use :c:func:`PyMem_Free` to free the buffer). @@ -375,8 +375,8 @@ incremented refcount. :class:`bytes`, :class:`bytearray` and other char buffer compatible objects - are decoded according to the given encoding and using the error handling - defined by errors. Both can be *NULL* to have the interface use the default + are decoded according to the given *encoding* and using the error handling + defined by *errors*. Both can be *NULL* to have the interface use the default values (see the next section for details). All other objects, including Unicode objects, cause a :exc:`TypeError` to be @@ -470,12 +470,12 @@ wchar_t Support """"""""""""""" -wchar_t support for platforms which support it: +:c:type:`wchar_t` support for platforms which support it: .. c:function:: PyObject* PyUnicode_FromWideChar(const wchar_t *w, Py_ssize_t size) - Create a Unicode object from the :c:type:`wchar_t` buffer *w* of the given size. - Passing -1 as the size indicates that the function must itself compute the length, + Create a Unicode object from the :c:type:`wchar_t` buffer *w* of the given *size*. + Passing -1 as the *size* indicates that the function must itself compute the length, using wcslen. Return *NULL* on failure. @@ -513,15 +513,15 @@ Python provides a set of built-in codecs which are written in C for speed. All of these codecs are directly usable via the following functions. -Many of the following APIs take two arguments encoding and errors. These -parameters encoding and errors have the same semantics as the ones of the -built-in :func:`str` string object constructor. +Many of the following APIs take two arguments encoding and errors, and they +have the same semantics as the ones of the built-in :func:`str` string object +constructor. Setting encoding to *NULL* causes the default encoding to be used which is ASCII. The file system calls should use :c:func:`PyUnicode_FSConverter` for encoding file names. This uses the variable :c:data:`Py_FileSystemDefaultEncoding` internally. This -variable should be treated as read-only: On some systems, it will be a +variable should be treated as read-only: on some systems, it will be a pointer to a static string, on others, it will change at run-time (such as when the application invokes setlocale). @@ -550,7 +550,7 @@ .. c:function:: PyObject* PyUnicode_Encode(const Py_UNICODE *s, Py_ssize_t size, const char *encoding, const char *errors) - Encode the :c:type:`Py_UNICODE` buffer of the given size and return a Python + Encode the :c:type:`Py_UNICODE` buffer *s* of the given *size* and return a Python bytes object. *encoding* and *errors* have the same meaning as the parameters of the same name in the Unicode :meth:`encode` method. The codec to be used is looked up using the Python codec registry. Return *NULL* if an @@ -588,7 +588,7 @@ .. c:function:: PyObject* PyUnicode_EncodeUTF8(const Py_UNICODE *s, Py_ssize_t size, const char *errors) - Encode the :c:type:`Py_UNICODE` buffer of the given size using UTF-8 and + Encode the :c:type:`Py_UNICODE` buffer *s* of the given *size* using UTF-8 and return a Python bytes object. Return *NULL* if an exception was raised by the codec. @@ -608,7 +608,7 @@ .. c:function:: PyObject* PyUnicode_DecodeUTF32(const char *s, Py_ssize_t size, const char *errors, int *byteorder) - Decode *length* bytes from a UTF-32 encoded buffer string and return the + Decode *size* bytes from a UTF-32 encoded buffer string and return the corresponding Unicode object. *errors* (if non-*NULL*) defines the error handling. It defaults to "strict". @@ -676,7 +676,7 @@ .. c:function:: PyObject* PyUnicode_DecodeUTF16(const char *s, Py_ssize_t size, const char *errors, int *byteorder) - Decode *length* bytes from a UTF-16 encoded buffer string and return the + Decode *size* bytes from a UTF-16 encoded buffer string and return the corresponding Unicode object. *errors* (if non-*NULL*) defines the error handling. It defaults to "strict". @@ -782,7 +782,7 @@ .. c:function:: PyObject* PyUnicode_EncodeUnicodeEscape(const Py_UNICODE *s, Py_ssize_t size) - Encode the :c:type:`Py_UNICODE` buffer of the given size using Unicode-Escape and + Encode the :c:type:`Py_UNICODE` buffer of the given *size* using Unicode-Escape and return a Python string object. Return *NULL* if an exception was raised by the codec. @@ -808,7 +808,7 @@ .. c:function:: PyObject* PyUnicode_EncodeRawUnicodeEscape(const Py_UNICODE *s, Py_ssize_t size, const char *errors) - Encode the :c:type:`Py_UNICODE` buffer of the given size using Raw-Unicode-Escape + Encode the :c:type:`Py_UNICODE` buffer of the given *size* using Raw-Unicode-Escape and return a Python string object. Return *NULL* if an exception was raised by the codec. @@ -835,7 +835,7 @@ .. c:function:: PyObject* PyUnicode_EncodeLatin1(const Py_UNICODE *s, Py_ssize_t size, const char *errors) - Encode the :c:type:`Py_UNICODE` buffer of the given size using Latin-1 and + Encode the :c:type:`Py_UNICODE` buffer of the given *size* using Latin-1 and return a Python bytes object. Return *NULL* if an exception was raised by the codec. @@ -862,7 +862,7 @@ .. c:function:: PyObject* PyUnicode_EncodeASCII(const Py_UNICODE *s, Py_ssize_t size, const char *errors) - Encode the :c:type:`Py_UNICODE` buffer of the given size using ASCII and + Encode the :c:type:`Py_UNICODE` buffer of the given *size* using ASCII and return a Python bytes object. Return *NULL* if an exception was raised by the codec. @@ -877,8 +877,6 @@ Character Map Codecs """""""""""""""""""" -These are the mapping codec APIs: - This codec is special in that it can be used to implement many different codecs (and this is in fact what was done to obtain most of the standard codecs included in the :mod:`encodings` package). The codec uses mapping to encode and @@ -900,6 +898,7 @@ resp. Because of this, mappings only need to contain those mappings which map characters to different code points. +These are the mapping codec APIs: .. c:function:: PyObject* PyUnicode_DecodeCharmap(const char *s, Py_ssize_t size, PyObject *mapping, const char *errors) @@ -913,7 +912,7 @@ .. c:function:: PyObject* PyUnicode_EncodeCharmap(const Py_UNICODE *s, Py_ssize_t size, PyObject *mapping, const char *errors) - Encode the :c:type:`Py_UNICODE` buffer of the given size using the given + Encode the :c:type:`Py_UNICODE` buffer of the given *size* using the given *mapping* object and return a Python string object. Return *NULL* if an exception was raised by the codec. @@ -929,7 +928,7 @@ .. c:function:: PyObject* PyUnicode_TranslateCharmap(const Py_UNICODE *s, Py_ssize_t size, PyObject *table, const char *errors) - Translate a :c:type:`Py_UNICODE` buffer of the given length by applying a + Translate a :c:type:`Py_UNICODE` buffer of the given *size* by applying a character mapping *table* to it and return the resulting Unicode object. Return *NULL* when an exception was raised by the codec. @@ -941,16 +940,15 @@ :exc:`LookupError`) are left untouched and are copied as-is. + +MBCS codecs for Windows +""""""""""""""""""""""" + These are the MBCS codec APIs. They are currently only available on Windows and use the Win32 MBCS converters to implement the conversions. Note that MBCS (or DBCS) is a class of encodings, not just one. The target encoding is defined by the user settings on the machine running the codec. - -MBCS codecs for Windows -""""""""""""""""""""""" - - .. c:function:: PyObject* PyUnicode_DecodeMBCS(const char *s, Py_ssize_t size, const char *errors) Create a Unicode object by decoding *size* bytes of the MBCS encoded string *s*. @@ -967,7 +965,7 @@ .. c:function:: PyObject* PyUnicode_EncodeMBCS(const Py_UNICODE *s, Py_ssize_t size, const char *errors) - Encode the :c:type:`Py_UNICODE` buffer of the given size using MBCS and return + Encode the :c:type:`Py_UNICODE` buffer of the given *size* using MBCS and return a Python bytes object. Return *NULL* if an exception was raised by the codec. @@ -1002,7 +1000,7 @@ .. c:function:: PyObject* PyUnicode_Split(PyObject *s, PyObject *sep, Py_ssize_t maxsplit) - Split a string giving a list of Unicode strings. If sep is *NULL*, splitting + Split a string giving a list of Unicode strings. If *sep* is *NULL*, splitting will be done at all whitespace substrings. Otherwise, splits occur at the given separator. At most *maxsplit* splits will be done. If negative, no limit is set. Separators are not included in the resulting list. @@ -1033,20 +1031,20 @@ .. c:function:: PyObject* PyUnicode_Join(PyObject *separator, PyObject *seq) - Join a sequence of strings using the given separator and return the resulting + Join a sequence of strings using the given *separator* and return the resulting Unicode string. .. c:function:: int PyUnicode_Tailmatch(PyObject *str, PyObject *substr, Py_ssize_t start, Py_ssize_t end, int direction) - Return 1 if *substr* matches *str*[*start*:*end*] at the given tail end + Return 1 if *substr* matches ``str[start:end]`` at the given tail end (*direction* == -1 means to do a prefix match, *direction* == 1 a suffix match), 0 otherwise. Return ``-1`` if an error occurred. .. c:function:: Py_ssize_t PyUnicode_Find(PyObject *str, PyObject *substr, Py_ssize_t start, Py_ssize_t end, int direction) - Return the first position of *substr* in *str*[*start*:*end*] using the given + Return the first position of *substr* in ``str[start:end]`` using the given *direction* (*direction* == 1 means to do a forward search, *direction* == -1 a backward search). The return value is the index of the first match; a value of ``-1`` indicates that no match was found, and ``-2`` indicates that an error -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Apr 14 06:54:20 2011 From: python-checkins at python.org (ezio.melotti) Date: Thu, 14 Apr 2011 06:54:20 +0200 Subject: [Python-checkins] cpython (2.7): #11840: Improve c-api/unicode documentation. Patch by Sandro Tosi. Message-ID: http://hg.python.org/cpython/rev/7f873729484c changeset: 69345:7f873729484c branch: 2.7 parent: 69341:5a09a335e8e7 user: Ezio Melotti date: Thu Apr 14 07:39:06 2011 +0300 summary: #11840: Improve c-api/unicode documentation. Patch by Sandro Tosi. files: Doc/c-api/unicode.rst | 53 +++++++++++++++--------------- 1 files changed, 26 insertions(+), 27 deletions(-) diff --git a/Doc/c-api/unicode.rst b/Doc/c-api/unicode.rst --- a/Doc/c-api/unicode.rst +++ b/Doc/c-api/unicode.rst @@ -371,11 +371,11 @@ wchar_t Support """"""""""""""" -wchar_t support for platforms which support it: +:ctype:`wchar_t` support for platforms which support it: .. cfunction:: PyObject* PyUnicode_FromWideChar(const wchar_t *w, Py_ssize_t size) - Create a Unicode object from the :ctype:`wchar_t` buffer *w* of the given size. + Create a Unicode object from the :ctype:`wchar_t` buffer *w* of the given *size*. Return *NULL* on failure. .. versionchanged:: 2.5 @@ -407,13 +407,13 @@ Python provides a set of built-in codecs which are written in C for speed. All of these codecs are directly usable via the following functions. -Many of the following APIs take two arguments encoding and errors. These -parameters encoding and errors have the same semantics as the ones of the -built-in :func:`unicode` Unicode object constructor. +Many of the following APIs take two arguments encoding and errors, and they +have the same semantics as the ones of the built-in :func:`unicode` Unicode +object constructor. Setting encoding to *NULL* causes the default encoding to be used which is ASCII. The file system calls should use :cdata:`Py_FileSystemDefaultEncoding` -as the encoding for file names. This variable should be treated as read-only: On +as the encoding for file names. This variable should be treated as read-only: on some systems, it will be a pointer to a static string, on others, it will change at run-time (such as when the application invokes setlocale). @@ -446,7 +446,7 @@ .. cfunction:: PyObject* PyUnicode_Encode(const Py_UNICODE *s, Py_ssize_t size, const char *encoding, const char *errors) - Encode the :ctype:`Py_UNICODE` buffer of the given size and return a Python + Encode the :ctype:`Py_UNICODE` buffer *s* of the given *size* and return a Python string object. *encoding* and *errors* have the same meaning as the parameters of the same name in the Unicode :meth:`encode` method. The codec to be used is looked up using the Python codec registry. Return *NULL* if an exception was @@ -498,7 +498,7 @@ .. cfunction:: PyObject* PyUnicode_EncodeUTF8(const Py_UNICODE *s, Py_ssize_t size, const char *errors) - Encode the :ctype:`Py_UNICODE` buffer of the given size using UTF-8 and return a + Encode the :ctype:`Py_UNICODE` buffer *s* of the given *size* using UTF-8 and return a Python string object. Return *NULL* if an exception was raised by the codec. .. versionchanged:: 2.5 @@ -521,7 +521,7 @@ .. cfunction:: PyObject* PyUnicode_DecodeUTF32(const char *s, Py_ssize_t size, const char *errors, int *byteorder) - Decode *length* bytes from a UTF-32 encoded buffer string and return the + Decode *size* bytes from a UTF-32 encoded buffer string and return the corresponding Unicode object. *errors* (if non-*NULL*) defines the error handling. It defaults to "strict". @@ -597,7 +597,7 @@ .. cfunction:: PyObject* PyUnicode_DecodeUTF16(const char *s, Py_ssize_t size, const char *errors, int *byteorder) - Decode *length* bytes from a UTF-16 encoded buffer string and return the + Decode *size* bytes from a UTF-16 encoded buffer string and return the corresponding Unicode object. *errors* (if non-*NULL*) defines the error handling. It defaults to "strict". @@ -722,7 +722,7 @@ .. cfunction:: PyObject* PyUnicode_EncodeUnicodeEscape(const Py_UNICODE *s, Py_ssize_t size) - Encode the :ctype:`Py_UNICODE` buffer of the given size using Unicode-Escape and + Encode the :ctype:`Py_UNICODE` buffer of the given *size* using Unicode-Escape and return a Python string object. Return *NULL* if an exception was raised by the codec. @@ -756,7 +756,7 @@ .. cfunction:: PyObject* PyUnicode_EncodeRawUnicodeEscape(const Py_UNICODE *s, Py_ssize_t size, const char *errors) - Encode the :ctype:`Py_UNICODE` buffer of the given size using Raw-Unicode-Escape + Encode the :ctype:`Py_UNICODE` buffer of the given *size* using Raw-Unicode-Escape and return a Python string object. Return *NULL* if an exception was raised by the codec. @@ -791,7 +791,7 @@ .. cfunction:: PyObject* PyUnicode_EncodeLatin1(const Py_UNICODE *s, Py_ssize_t size, const char *errors) - Encode the :ctype:`Py_UNICODE` buffer of the given size using Latin-1 and return + Encode the :ctype:`Py_UNICODE` buffer of the given *size* using Latin-1 and return a Python string object. Return *NULL* if an exception was raised by the codec. .. versionchanged:: 2.5 @@ -825,7 +825,7 @@ .. cfunction:: PyObject* PyUnicode_EncodeASCII(const Py_UNICODE *s, Py_ssize_t size, const char *errors) - Encode the :ctype:`Py_UNICODE` buffer of the given size using ASCII and return a + Encode the :ctype:`Py_UNICODE` buffer of the given *size* using ASCII and return a Python string object. Return *NULL* if an exception was raised by the codec. .. versionchanged:: 2.5 @@ -843,8 +843,6 @@ Character Map Codecs """""""""""""""""""" -These are the mapping codec APIs: - This codec is special in that it can be used to implement many different codecs (and this is in fact what was done to obtain most of the standard codecs included in the :mod:`encodings` package). The codec uses mapping to encode and @@ -866,6 +864,7 @@ resp. Because of this, mappings only need to contain those mappings which map characters to different code points. +These are the mapping codec APIs: .. cfunction:: PyObject* PyUnicode_DecodeCharmap(const char *s, Py_ssize_t size, PyObject *mapping, const char *errors) @@ -886,7 +885,7 @@ .. cfunction:: PyObject* PyUnicode_EncodeCharmap(const Py_UNICODE *s, Py_ssize_t size, PyObject *mapping, const char *errors) - Encode the :ctype:`Py_UNICODE` buffer of the given size using the given + Encode the :ctype:`Py_UNICODE` buffer of the given *size* using the given *mapping* object and return a Python string object. Return *NULL* if an exception was raised by the codec. @@ -906,7 +905,7 @@ .. cfunction:: PyObject* PyUnicode_TranslateCharmap(const Py_UNICODE *s, Py_ssize_t size, PyObject *table, const char *errors) - Translate a :ctype:`Py_UNICODE` buffer of the given length by applying a + Translate a :ctype:`Py_UNICODE` buffer of the given *size* by applying a character mapping *table* to it and return the resulting Unicode object. Return *NULL* when an exception was raised by the codec. @@ -921,16 +920,16 @@ This function used an :ctype:`int` type for *size*. This might require changes in your code for properly supporting 64-bit systems. + +MBCS codecs for Windows +""""""""""""""""""""""" + These are the MBCS codec APIs. They are currently only available on Windows and use the Win32 MBCS converters to implement the conversions. Note that MBCS (or DBCS) is a class of encodings, not just one. The target encoding is defined by the user settings on the machine running the codec. -MBCS codecs for Windows -""""""""""""""""""""""" - - .. cfunction:: PyObject* PyUnicode_DecodeMBCS(const char *s, Py_ssize_t size, const char *errors) Create a Unicode object by decoding *size* bytes of the MBCS encoded string *s*. @@ -953,7 +952,7 @@ .. cfunction:: PyObject* PyUnicode_EncodeMBCS(const Py_UNICODE *s, Py_ssize_t size, const char *errors) - Encode the :ctype:`Py_UNICODE` buffer of the given size using MBCS and return a + Encode the :ctype:`Py_UNICODE` buffer of the given *size* using MBCS and return a Python string object. Return *NULL* if an exception was raised by the codec. .. versionchanged:: 2.5 @@ -990,7 +989,7 @@ .. cfunction:: PyObject* PyUnicode_Split(PyObject *s, PyObject *sep, Py_ssize_t maxsplit) - Split a string giving a list of Unicode strings. If sep is *NULL*, splitting + Split a string giving a list of Unicode strings. If *sep* is *NULL*, splitting will be done at all whitespace substrings. Otherwise, splits occur at the given separator. At most *maxsplit* splits will be done. If negative, no limit is set. Separators are not included in the resulting list. @@ -1025,13 +1024,13 @@ .. cfunction:: PyObject* PyUnicode_Join(PyObject *separator, PyObject *seq) - Join a sequence of strings using the given separator and return the resulting + Join a sequence of strings using the given *separator* and return the resulting Unicode string. .. cfunction:: int PyUnicode_Tailmatch(PyObject *str, PyObject *substr, Py_ssize_t start, Py_ssize_t end, int direction) - Return 1 if *substr* matches *str*[*start*:*end*] at the given tail end + Return 1 if *substr* matches ``str[start:end]`` at the given tail end (*direction* == -1 means to do a prefix match, *direction* == 1 a suffix match), 0 otherwise. Return ``-1`` if an error occurred. @@ -1043,7 +1042,7 @@ .. cfunction:: Py_ssize_t PyUnicode_Find(PyObject *str, PyObject *substr, Py_ssize_t start, Py_ssize_t end, int direction) - Return the first position of *substr* in *str*[*start*:*end*] using the given + Return the first position of *substr* in ``str[start:end]`` using the given *direction* (*direction* == 1 means to do a forward search, *direction* == -1 a backward search). The return value is the index of the first match; a value of ``-1`` indicates that no match was found, and ``-2`` indicates that an error -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Apr 14 06:59:02 2011 From: python-checkins at python.org (senthil.kumaran) Date: Thu, 14 Apr 2011 06:59:02 +0200 Subject: [Python-checkins] cpython (2.7): Fix Issue11474 - url2pathname() handling of '/C|/' on Windows Message-ID: http://hg.python.org/cpython/rev/4556f17356f2 changeset: 69346:4556f17356f2 branch: 2.7 parent: 69341:5a09a335e8e7 user: Senthil Kumaran date: Thu Apr 14 12:54:35 2011 +0800 summary: Fix Issue11474 - url2pathname() handling of '/C|/' on Windows files: Lib/nturl2path.py | 7 +++++-- Lib/test/test_urllib.py | 18 ++++++++++++++++++ Misc/NEWS | 3 +++ 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/Lib/nturl2path.py b/Lib/nturl2path.py --- a/Lib/nturl2path.py +++ b/Lib/nturl2path.py @@ -25,11 +25,14 @@ error = 'Bad URL: ' + url raise IOError, error drive = comp[0][-1].upper() + path = drive + ':' components = comp[1].split('/') - path = drive + ':' - for comp in components: + for comp in components: if comp: path = path + '\\' + urllib.unquote(comp) + # Issue #11474: url like '/C|/' should convert into 'C:\\' + if path.endswith(':') and url.endswith('/'): + path += '\\' return path def pathname2url(p): diff --git a/Lib/test/test_urllib.py b/Lib/test/test_urllib.py --- a/Lib/test/test_urllib.py +++ b/Lib/test/test_urllib.py @@ -5,6 +5,7 @@ import unittest from test import test_support import os +import sys import mimetools import tempfile import StringIO @@ -630,6 +631,23 @@ "url2pathname() failed; %s != %s" % (expect, result)) + @unittest.skipUnless(sys.platform == 'win32', + 'test specific to the nturl2path library') + def test_ntpath(self): + given = ('/C:/', '///C:/', '/C|//') + expect = 'C:\\' + for url in given: + result = urllib.url2pathname(url) + self.assertEqual(expect, result, + 'nturl2path.url2pathname() failed; %s != %s' % + (expect, result)) + given = '///C|/path' + expect = 'C:\\path' + result = urllib.url2pathname(given) + self.assertEqual(expect, result, + 'nturl2path.url2pathname() failed; %s != %s' % + (expect, result)) + class Utility_Tests(unittest.TestCase): """Testcase to test the various utility functions in the urllib.""" diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -51,6 +51,9 @@ Library ------- +- Issue #11474: Fix the bug with url2pathname() handling of '/C|/' on Windows. + Patch by Santoso Wijaya. + - Issue #9233: Fix json.loads('{}') to return a dict (instead of a list), when _json is not available. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Apr 14 06:59:04 2011 From: python-checkins at python.org (senthil.kumaran) Date: Thu, 14 Apr 2011 06:59:04 +0200 Subject: [Python-checkins] cpython (merge 2.7 -> 2.7): merge the changes. Message-ID: http://hg.python.org/cpython/rev/9cfb90c883af changeset: 69347:9cfb90c883af branch: 2.7 parent: 69346:4556f17356f2 parent: 69345:7f873729484c user: Senthil Kumaran date: Thu Apr 14 12:58:32 2011 +0800 summary: merge the changes. files: Doc/c-api/unicode.rst | 53 +++++++++++++++--------------- 1 files changed, 26 insertions(+), 27 deletions(-) diff --git a/Doc/c-api/unicode.rst b/Doc/c-api/unicode.rst --- a/Doc/c-api/unicode.rst +++ b/Doc/c-api/unicode.rst @@ -371,11 +371,11 @@ wchar_t Support """"""""""""""" -wchar_t support for platforms which support it: +:ctype:`wchar_t` support for platforms which support it: .. cfunction:: PyObject* PyUnicode_FromWideChar(const wchar_t *w, Py_ssize_t size) - Create a Unicode object from the :ctype:`wchar_t` buffer *w* of the given size. + Create a Unicode object from the :ctype:`wchar_t` buffer *w* of the given *size*. Return *NULL* on failure. .. versionchanged:: 2.5 @@ -407,13 +407,13 @@ Python provides a set of built-in codecs which are written in C for speed. All of these codecs are directly usable via the following functions. -Many of the following APIs take two arguments encoding and errors. These -parameters encoding and errors have the same semantics as the ones of the -built-in :func:`unicode` Unicode object constructor. +Many of the following APIs take two arguments encoding and errors, and they +have the same semantics as the ones of the built-in :func:`unicode` Unicode +object constructor. Setting encoding to *NULL* causes the default encoding to be used which is ASCII. The file system calls should use :cdata:`Py_FileSystemDefaultEncoding` -as the encoding for file names. This variable should be treated as read-only: On +as the encoding for file names. This variable should be treated as read-only: on some systems, it will be a pointer to a static string, on others, it will change at run-time (such as when the application invokes setlocale). @@ -446,7 +446,7 @@ .. cfunction:: PyObject* PyUnicode_Encode(const Py_UNICODE *s, Py_ssize_t size, const char *encoding, const char *errors) - Encode the :ctype:`Py_UNICODE` buffer of the given size and return a Python + Encode the :ctype:`Py_UNICODE` buffer *s* of the given *size* and return a Python string object. *encoding* and *errors* have the same meaning as the parameters of the same name in the Unicode :meth:`encode` method. The codec to be used is looked up using the Python codec registry. Return *NULL* if an exception was @@ -498,7 +498,7 @@ .. cfunction:: PyObject* PyUnicode_EncodeUTF8(const Py_UNICODE *s, Py_ssize_t size, const char *errors) - Encode the :ctype:`Py_UNICODE` buffer of the given size using UTF-8 and return a + Encode the :ctype:`Py_UNICODE` buffer *s* of the given *size* using UTF-8 and return a Python string object. Return *NULL* if an exception was raised by the codec. .. versionchanged:: 2.5 @@ -521,7 +521,7 @@ .. cfunction:: PyObject* PyUnicode_DecodeUTF32(const char *s, Py_ssize_t size, const char *errors, int *byteorder) - Decode *length* bytes from a UTF-32 encoded buffer string and return the + Decode *size* bytes from a UTF-32 encoded buffer string and return the corresponding Unicode object. *errors* (if non-*NULL*) defines the error handling. It defaults to "strict". @@ -597,7 +597,7 @@ .. cfunction:: PyObject* PyUnicode_DecodeUTF16(const char *s, Py_ssize_t size, const char *errors, int *byteorder) - Decode *length* bytes from a UTF-16 encoded buffer string and return the + Decode *size* bytes from a UTF-16 encoded buffer string and return the corresponding Unicode object. *errors* (if non-*NULL*) defines the error handling. It defaults to "strict". @@ -722,7 +722,7 @@ .. cfunction:: PyObject* PyUnicode_EncodeUnicodeEscape(const Py_UNICODE *s, Py_ssize_t size) - Encode the :ctype:`Py_UNICODE` buffer of the given size using Unicode-Escape and + Encode the :ctype:`Py_UNICODE` buffer of the given *size* using Unicode-Escape and return a Python string object. Return *NULL* if an exception was raised by the codec. @@ -756,7 +756,7 @@ .. cfunction:: PyObject* PyUnicode_EncodeRawUnicodeEscape(const Py_UNICODE *s, Py_ssize_t size, const char *errors) - Encode the :ctype:`Py_UNICODE` buffer of the given size using Raw-Unicode-Escape + Encode the :ctype:`Py_UNICODE` buffer of the given *size* using Raw-Unicode-Escape and return a Python string object. Return *NULL* if an exception was raised by the codec. @@ -791,7 +791,7 @@ .. cfunction:: PyObject* PyUnicode_EncodeLatin1(const Py_UNICODE *s, Py_ssize_t size, const char *errors) - Encode the :ctype:`Py_UNICODE` buffer of the given size using Latin-1 and return + Encode the :ctype:`Py_UNICODE` buffer of the given *size* using Latin-1 and return a Python string object. Return *NULL* if an exception was raised by the codec. .. versionchanged:: 2.5 @@ -825,7 +825,7 @@ .. cfunction:: PyObject* PyUnicode_EncodeASCII(const Py_UNICODE *s, Py_ssize_t size, const char *errors) - Encode the :ctype:`Py_UNICODE` buffer of the given size using ASCII and return a + Encode the :ctype:`Py_UNICODE` buffer of the given *size* using ASCII and return a Python string object. Return *NULL* if an exception was raised by the codec. .. versionchanged:: 2.5 @@ -843,8 +843,6 @@ Character Map Codecs """""""""""""""""""" -These are the mapping codec APIs: - This codec is special in that it can be used to implement many different codecs (and this is in fact what was done to obtain most of the standard codecs included in the :mod:`encodings` package). The codec uses mapping to encode and @@ -866,6 +864,7 @@ resp. Because of this, mappings only need to contain those mappings which map characters to different code points. +These are the mapping codec APIs: .. cfunction:: PyObject* PyUnicode_DecodeCharmap(const char *s, Py_ssize_t size, PyObject *mapping, const char *errors) @@ -886,7 +885,7 @@ .. cfunction:: PyObject* PyUnicode_EncodeCharmap(const Py_UNICODE *s, Py_ssize_t size, PyObject *mapping, const char *errors) - Encode the :ctype:`Py_UNICODE` buffer of the given size using the given + Encode the :ctype:`Py_UNICODE` buffer of the given *size* using the given *mapping* object and return a Python string object. Return *NULL* if an exception was raised by the codec. @@ -906,7 +905,7 @@ .. cfunction:: PyObject* PyUnicode_TranslateCharmap(const Py_UNICODE *s, Py_ssize_t size, PyObject *table, const char *errors) - Translate a :ctype:`Py_UNICODE` buffer of the given length by applying a + Translate a :ctype:`Py_UNICODE` buffer of the given *size* by applying a character mapping *table* to it and return the resulting Unicode object. Return *NULL* when an exception was raised by the codec. @@ -921,16 +920,16 @@ This function used an :ctype:`int` type for *size*. This might require changes in your code for properly supporting 64-bit systems. + +MBCS codecs for Windows +""""""""""""""""""""""" + These are the MBCS codec APIs. They are currently only available on Windows and use the Win32 MBCS converters to implement the conversions. Note that MBCS (or DBCS) is a class of encodings, not just one. The target encoding is defined by the user settings on the machine running the codec. -MBCS codecs for Windows -""""""""""""""""""""""" - - .. cfunction:: PyObject* PyUnicode_DecodeMBCS(const char *s, Py_ssize_t size, const char *errors) Create a Unicode object by decoding *size* bytes of the MBCS encoded string *s*. @@ -953,7 +952,7 @@ .. cfunction:: PyObject* PyUnicode_EncodeMBCS(const Py_UNICODE *s, Py_ssize_t size, const char *errors) - Encode the :ctype:`Py_UNICODE` buffer of the given size using MBCS and return a + Encode the :ctype:`Py_UNICODE` buffer of the given *size* using MBCS and return a Python string object. Return *NULL* if an exception was raised by the codec. .. versionchanged:: 2.5 @@ -990,7 +989,7 @@ .. cfunction:: PyObject* PyUnicode_Split(PyObject *s, PyObject *sep, Py_ssize_t maxsplit) - Split a string giving a list of Unicode strings. If sep is *NULL*, splitting + Split a string giving a list of Unicode strings. If *sep* is *NULL*, splitting will be done at all whitespace substrings. Otherwise, splits occur at the given separator. At most *maxsplit* splits will be done. If negative, no limit is set. Separators are not included in the resulting list. @@ -1025,13 +1024,13 @@ .. cfunction:: PyObject* PyUnicode_Join(PyObject *separator, PyObject *seq) - Join a sequence of strings using the given separator and return the resulting + Join a sequence of strings using the given *separator* and return the resulting Unicode string. .. cfunction:: int PyUnicode_Tailmatch(PyObject *str, PyObject *substr, Py_ssize_t start, Py_ssize_t end, int direction) - Return 1 if *substr* matches *str*[*start*:*end*] at the given tail end + Return 1 if *substr* matches ``str[start:end]`` at the given tail end (*direction* == -1 means to do a prefix match, *direction* == 1 a suffix match), 0 otherwise. Return ``-1`` if an error occurred. @@ -1043,7 +1042,7 @@ .. cfunction:: Py_ssize_t PyUnicode_Find(PyObject *str, PyObject *substr, Py_ssize_t start, Py_ssize_t end, int direction) - Return the first position of *substr* in *str*[*start*:*end*] using the given + Return the first position of *substr* in ``str[start:end]`` using the given *direction* (*direction* == 1 means to do a forward search, *direction* == -1 a backward search). The return value is the index of the first match; a value of ``-1`` indicates that no match was found, and ``-2`` indicates that an error -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Apr 14 07:20:58 2011 From: python-checkins at python.org (senthil.kumaran) Date: Thu, 14 Apr 2011 07:20:58 +0200 Subject: [Python-checkins] cpython (3.1): Fix Issue11474 - fix url2pathname() handling of '/C|/' on Windows Message-ID: http://hg.python.org/cpython/rev/de0da2759c8c changeset: 69348:de0da2759c8c branch: 3.1 parent: 69342:11c72a305eb5 user: Senthil Kumaran date: Thu Apr 14 13:16:30 2011 +0800 summary: Fix Issue11474 - fix url2pathname() handling of '/C|/' on Windows files: Lib/nturl2path.py | 5 ++++- Lib/test/test_urllib.py | 18 ++++++++++++++++++ Misc/NEWS | 3 +++ 3 files changed, 25 insertions(+), 1 deletions(-) diff --git a/Lib/nturl2path.py b/Lib/nturl2path.py --- a/Lib/nturl2path.py +++ b/Lib/nturl2path.py @@ -27,9 +27,12 @@ drive = comp[0][-1].upper() components = comp[1].split('/') path = drive + ':' - for comp in components: + for comp in components: if comp: path = path + '\\' + urllib.parse.unquote(comp) + # Issue #11474 - handing url such as |c/| + if path.endswith(':') and url.endswith('/'): + path += '\\' return path def pathname2url(p): diff --git a/Lib/test/test_urllib.py b/Lib/test/test_urllib.py --- a/Lib/test/test_urllib.py +++ b/Lib/test/test_urllib.py @@ -9,6 +9,7 @@ import unittest from test import support import os +import sys import tempfile import warnings @@ -995,6 +996,23 @@ "url2pathname() failed; %s != %s" % (expect, result)) + @unittest.skipUnless(sys.platform == 'win32', + 'test specific to the urllib.url2path function.') + def test_ntpath(self): + given = ('/C:/', '///C:/', '/C|//') + expect = 'C:\\' + for url in given: + result = urllib.request.url2pathname(url) + self.assertEqual(expect, result, + 'urllib.request..url2pathname() failed; %s != %s' % + (expect, result)) + given = '///C|/path' + expect = 'C:\\path' + result = urllib.request.url2pathname(given) + self.assertEqual(expect, result, + 'urllib.request.url2pathname() failed; %s != %s' % + (expect, result)) + class Utility_Tests(unittest.TestCase): """Testcase to test the various utility functions in the urllib.""" diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -51,6 +51,9 @@ Library ------- +- Issue #11474: Fix the bug with url2pathname() handling of '/C|/' on Windows. + Patch by Santoso Wijaya. + - Issue #9233: Fix json to work properly even when _json is not available. - Issue #11703: urllib2.geturl() does not return correct url when the original -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Apr 14 07:20:59 2011 From: python-checkins at python.org (senthil.kumaran) Date: Thu, 14 Apr 2011 07:20:59 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): merge from 3.1 Message-ID: http://hg.python.org/cpython/rev/37d1b749eebb changeset: 69349:37d1b749eebb branch: 3.2 parent: 69343:62679f2ca9e5 parent: 69348:de0da2759c8c user: Senthil Kumaran date: Thu Apr 14 13:18:55 2011 +0800 summary: merge from 3.1 files: Lib/nturl2path.py | 5 ++++- Lib/test/test_urllib.py | 18 ++++++++++++++++++ Misc/NEWS | 3 +++ 3 files changed, 25 insertions(+), 1 deletions(-) diff --git a/Lib/nturl2path.py b/Lib/nturl2path.py --- a/Lib/nturl2path.py +++ b/Lib/nturl2path.py @@ -27,9 +27,12 @@ drive = comp[0][-1].upper() components = comp[1].split('/') path = drive + ':' - for comp in components: + for comp in components: if comp: path = path + '\\' + urllib.parse.unquote(comp) + # Issue #11474 - handing url such as |c/| + if path.endswith(':') and url.endswith('/'): + path += '\\' return path def pathname2url(p): diff --git a/Lib/test/test_urllib.py b/Lib/test/test_urllib.py --- a/Lib/test/test_urllib.py +++ b/Lib/test/test_urllib.py @@ -9,6 +9,7 @@ import unittest from test import support import os +import sys import tempfile def hexescape(char): @@ -1021,6 +1022,23 @@ "url2pathname() failed; %s != %s" % (expect, result)) + @unittest.skipUnless(sys.platform == 'win32', + 'test specific to the urllib.url2path function.') + def test_ntpath(self): + given = ('/C:/', '///C:/', '/C|//') + expect = 'C:\\' + for url in given: + result = urllib.request.url2pathname(url) + self.assertEqual(expect, result, + 'urllib.request..url2pathname() failed; %s != %s' % + (expect, result)) + given = '///C|/path' + expect = 'C:\\path' + result = urllib.request.url2pathname(given) + self.assertEqual(expect, result, + 'urllib.request.url2pathname() failed; %s != %s' % + (expect, result)) + class Utility_Tests(unittest.TestCase): """Testcase to test the various utility functions in the urllib.""" diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -53,6 +53,9 @@ Library ------- +- Issue #11474: Fix the bug with url2pathname() handling of '/C|/' on Windows. + Patch by Santoso Wijaya. + - Issue #9233: Fix json.loads('{}') to return a dict (instead of a list), when _json is not available. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Apr 14 07:21:00 2011 From: python-checkins at python.org (senthil.kumaran) Date: Thu, 14 Apr 2011 07:21:00 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): merge from 3.2. Message-ID: http://hg.python.org/cpython/rev/7563f10275a2 changeset: 69350:7563f10275a2 parent: 69344:1f767f834e67 parent: 69349:37d1b749eebb user: Senthil Kumaran date: Thu Apr 14 13:20:41 2011 +0800 summary: merge from 3.2. Fix closes Issue1147. files: Lib/nturl2path.py | 5 ++++- Lib/test/test_urllib.py | 18 ++++++++++++++++++ Misc/NEWS | 3 +++ 3 files changed, 25 insertions(+), 1 deletions(-) diff --git a/Lib/nturl2path.py b/Lib/nturl2path.py --- a/Lib/nturl2path.py +++ b/Lib/nturl2path.py @@ -27,9 +27,12 @@ drive = comp[0][-1].upper() components = comp[1].split('/') path = drive + ':' - for comp in components: + for comp in components: if comp: path = path + '\\' + urllib.parse.unquote(comp) + # Issue #11474 - handing url such as |c/| + if path.endswith(':') and url.endswith('/'): + path += '\\' return path def pathname2url(p): diff --git a/Lib/test/test_urllib.py b/Lib/test/test_urllib.py --- a/Lib/test/test_urllib.py +++ b/Lib/test/test_urllib.py @@ -9,6 +9,7 @@ import unittest from test import support import os +import sys import tempfile def hexescape(char): @@ -1021,6 +1022,23 @@ "url2pathname() failed; %s != %s" % (expect, result)) + @unittest.skipUnless(sys.platform == 'win32', + 'test specific to the urllib.url2path function.') + def test_ntpath(self): + given = ('/C:/', '///C:/', '/C|//') + expect = 'C:\\' + for url in given: + result = urllib.request.url2pathname(url) + self.assertEqual(expect, result, + 'urllib.request..url2pathname() failed; %s != %s' % + (expect, result)) + given = '///C|/path' + expect = 'C:\\path' + result = urllib.request.url2pathname(given) + self.assertEqual(expect, result, + 'urllib.request.url2pathname() failed; %s != %s' % + (expect, result)) + class Utility_Tests(unittest.TestCase): """Testcase to test the various utility functions in the urllib.""" diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -103,6 +103,9 @@ Library ------- +- Issue #11474: Fix the bug with url2pathname() handling of '/C|/' on Windows. + Patch by Santoso Wijaya. + - Issue #11684: complete email.parser bytes API by adding BytesHeaderParser. - The bz2 module now handles 4GiB+ input buffers correctly. -- Repository URL: http://hg.python.org/cpython From brett at python.org Thu Apr 14 20:53:56 2011 From: brett at python.org (Brett Cannon) Date: Thu, 14 Apr 2011 11:53:56 -0700 Subject: [Python-checkins] cpython (merge 3.2 -> default): merge from 3.2. In-Reply-To: References: Message-ID: I think you have the wrong issue #; that one has to do with string exceptions. On Wed, Apr 13, 2011 at 22:21, senthil.kumaran wrote: > http://hg.python.org/cpython/rev/7563f10275a2 > changeset: 69350:7563f10275a2 > parent: 69344:1f767f834e67 > parent: 69349:37d1b749eebb > user: Senthil Kumaran > date: Thu Apr 14 13:20:41 2011 +0800 > summary: > merge from 3.2. > > Fix closes Issue1147. > > files: > Lib/nturl2path.py | 5 ++++- > Lib/test/test_urllib.py | 18 ++++++++++++++++++ > Misc/NEWS | 3 +++ > 3 files changed, 25 insertions(+), 1 deletions(-) > > > diff --git a/Lib/nturl2path.py b/Lib/nturl2path.py > --- a/Lib/nturl2path.py > +++ b/Lib/nturl2path.py > @@ -27,9 +27,12 @@ > drive = comp[0][-1].upper() > components = comp[1].split('/') > path = drive + ':' > - for comp in components: > + for comp in components: > if comp: > path = path + '\\' + urllib.parse.unquote(comp) > + # Issue #11474 - handing url such as |c/| > + if path.endswith(':') and url.endswith('/'): > + path += '\\' > return path > > def pathname2url(p): > diff --git a/Lib/test/test_urllib.py b/Lib/test/test_urllib.py > --- a/Lib/test/test_urllib.py > +++ b/Lib/test/test_urllib.py > @@ -9,6 +9,7 @@ > import unittest > from test import support > import os > +import sys > import tempfile > > def hexescape(char): > @@ -1021,6 +1022,23 @@ > "url2pathname() failed; %s != %s" % > (expect, result)) > > + @unittest.skipUnless(sys.platform == 'win32', > + 'test specific to the urllib.url2path function.') > + def test_ntpath(self): > + given = ('/C:/', '///C:/', '/C|//') > + expect = 'C:\\' > + for url in given: > + result = urllib.request.url2pathname(url) > + self.assertEqual(expect, result, > + 'urllib.request..url2pathname() failed; %s != > %s' % > + (expect, result)) > + given = '///C|/path' > + expect = 'C:\\path' > + result = urllib.request.url2pathname(given) > + self.assertEqual(expect, result, > + 'urllib.request.url2pathname() failed; %s != %s' > % > + (expect, result)) > + > class Utility_Tests(unittest.TestCase): > """Testcase to test the various utility functions in the urllib.""" > > diff --git a/Misc/NEWS b/Misc/NEWS > --- a/Misc/NEWS > +++ b/Misc/NEWS > @@ -103,6 +103,9 @@ > Library > ------- > > +- Issue #11474: Fix the bug with url2pathname() handling of '/C|/' on > Windows. > + Patch by Santoso Wijaya. > + > - Issue #11684: complete email.parser bytes API by adding > BytesHeaderParser. > > - The bz2 module now handles 4GiB+ input buffers correctly. > > -- > Repository URL: http://hg.python.org/cpython > > _______________________________________________ > Python-checkins mailing list > Python-checkins at python.org > http://mail.python.org/mailman/listinfo/python-checkins > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From python-checkins at python.org Thu Apr 14 21:27:59 2011 From: python-checkins at python.org (martin.v.loewis) Date: Thu, 14 Apr 2011 21:27:59 +0200 (CEST) Subject: [Python-checkins] r88814 - tracker/instances/python-dev/detectors/textplain.py Message-ID: <3Q9X8b0LXxz7LjZ@mail.python.org> Author: martin.v.loewis Date: Thu Apr 14 21:27:58 2011 New Revision: 88814 Log: Add detector to change application/octet-stream to text/plain sometimes. Added: tracker/instances/python-dev/detectors/textplain.py - copied, changed from r88813, /tracker/instances/python-dev/detectors/no_texthtml.py Copied: tracker/instances/python-dev/detectors/textplain.py (from r88813, /tracker/instances/python-dev/detectors/no_texthtml.py) ============================================================================== --- /tracker/instances/python-dev/detectors/no_texthtml.py (original) +++ tracker/instances/python-dev/detectors/textplain.py Thu Apr 14 21:27:58 2011 @@ -1,9 +1,21 @@ - -def audit_html_files(db, cl, nodeid, newvalues): - if newvalues.has_key('type') and newvalues['type'] == 'text/html': +# On file creation, if the file is application/octet-stream, +# yet the file content looks like text, change the type to +# text/plain. +def audit_application_octetstream(db, cl, nodeid, newvalues): + if newvalues.has_key('type') and newvalues['type'] == 'application/octet-stream': + # check whether this might be a text file + try: + text = newvalues['content'].decode('utf-8') + except UnicodeError: + return + # check that there aren't funny control characters in there + for c in text: + if ord(c) >= 32: + continue + if c not in u' \f\t\r\n': + return newvalues['type'] = 'text/plain' def init(db): - db.file.audit('set', audit_html_files) - db.file.audit('create', audit_html_files) + db.file.audit('create', audit_application_octetstream) From solipsis at pitrou.net Fri Apr 15 04:59:25 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Fri, 15 Apr 2011 04:59:25 +0200 Subject: [Python-checkins] Daily reference leaks (7563f10275a2): sum=0 Message-ID: results for 7563f10275a2 on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogovwVqV', '-x'] From python-checkins at python.org Fri Apr 15 06:29:40 2011 From: python-checkins at python.org (eli.bendersky) Date: Fri, 15 Apr 2011 06:29:40 +0200 Subject: [Python-checkins] cpython (3.1): Issue #11827: remove mention of list2cmdline in the doc of subprocess Message-ID: http://hg.python.org/cpython/rev/e7a55e236b8b changeset: 69351:e7a55e236b8b branch: 3.1 parent: 69348:de0da2759c8c user: Eli Bendersky date: Fri Apr 15 07:23:26 2011 +0300 summary: Issue #11827: remove mention of list2cmdline in the doc of subprocess files: Doc/library/subprocess.rst | 43 ++++++++++++++++++++++--- 1 files changed, 37 insertions(+), 6 deletions(-) diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst --- a/Doc/library/subprocess.rst +++ b/Doc/library/subprocess.rst @@ -93,12 +93,10 @@ *shell=False* does not suffer from this vulnerability; the above Note may be helpful in getting code using *shell=False* to work. - On Windows: the :class:`Popen` class uses CreateProcess() to execute the child - program, which operates on strings. If *args* is a sequence, it will be - converted to a string using the :meth:`list2cmdline` method. Please note that - not all MS Windows applications interpret the command line the same way: - :meth:`list2cmdline` is designed for applications using the same rules as the MS - C runtime. + On Windows: the :class:`Popen` class uses CreateProcess() to execute the + child program, which operates on strings. If *args* is a sequence, it will + be converted to a string in a manner described in + :ref:`converting-argument-sequence`. *bufsize*, if given, has the same meaning as the corresponding argument to the built-in open() function: :const:`0` means unbuffered, :const:`1` means line @@ -609,3 +607,36 @@ * popen2 closes all file descriptors by default, but you have to specify ``close_fds=True`` with :class:`Popen`. + +Notes +----- + +.. _converting-argument-sequence: + +Converting an argument sequence to a string on Windows +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +On Windows, an *args* sequence is converted to a string that can be parsed +using the following rules (which correspond to the rules used by the MS C +runtime): + +1. Arguments are delimited by white space, which is either a + space or a tab. + +2. A string surrounded by double quotation marks is + interpreted as a single argument, regardless of white space + contained within. A quoted string can be embedded in an + argument. + +3. A double quotation mark preceded by a backslash is + interpreted as a literal double quotation mark. + +4. Backslashes are interpreted literally, unless they + immediately precede a double quotation mark. + +5. If backslashes immediately precede a double quotation mark, + every pair of backslashes is interpreted as a literal + backslash. If the number of backslashes is odd, the last + backslash escapes the next double quotation mark as + described in rule 3. + -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 15 06:29:42 2011 From: python-checkins at python.org (eli.bendersky) Date: Fri, 15 Apr 2011 06:29:42 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): merge from 3.1 Message-ID: http://hg.python.org/cpython/rev/d8f8e20719b8 changeset: 69352:d8f8e20719b8 branch: 3.2 parent: 69349:37d1b749eebb parent: 69351:e7a55e236b8b user: Eli Bendersky date: Fri Apr 15 07:26:28 2011 +0300 summary: merge from 3.1 files: Doc/library/subprocess.rst | 44 ++++++++++++++++++++++--- 1 files changed, 38 insertions(+), 6 deletions(-) diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst --- a/Doc/library/subprocess.rst +++ b/Doc/library/subprocess.rst @@ -94,12 +94,10 @@ *shell=False* does not suffer from this vulnerability; the above Note may be helpful in getting code using *shell=False* to work. - On Windows: the :class:`Popen` class uses CreateProcess() to execute the child - program, which operates on strings. If *args* is a sequence, it will be - converted to a string using the :meth:`list2cmdline` method. Please note that - not all MS Windows applications interpret the command line the same way: - :meth:`list2cmdline` is designed for applications using the same rules as the MS - C runtime. + On Windows: the :class:`Popen` class uses CreateProcess() to execute the + child program, which operates on strings. If *args* is a sequence, it will + be converted to a string in a manner described in + :ref:`converting-argument-sequence`. *bufsize*, if given, has the same meaning as the corresponding argument to the built-in open() function: :const:`0` means unbuffered, :const:`1` means line @@ -664,3 +662,37 @@ * popen2 closes all file descriptors by default, but you have to specify ``close_fds=True`` with :class:`Popen` to guarantee this behavior on all platforms or past Python versions. + +Notes +----- + +.. _converting-argument-sequence: + +Converting an argument sequence to a string on Windows +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +On Windows, an *args* sequence is converted to a string that can be parsed +using the following rules (which correspond to the rules used by the MS C +runtime): + +1. Arguments are delimited by white space, which is either a + space or a tab. + +2. A string surrounded by double quotation marks is + interpreted as a single argument, regardless of white space + contained within. A quoted string can be embedded in an + argument. + +3. A double quotation mark preceded by a backslash is + interpreted as a literal double quotation mark. + +4. Backslashes are interpreted literally, unless they + immediately precede a double quotation mark. + +5. If backslashes immediately precede a double quotation mark, + every pair of backslashes is interpreted as a literal + backslash. If the number of backslashes is odd, the last + backslash escapes the next double quotation mark as + described in rule 3. + + -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 15 06:29:43 2011 From: python-checkins at python.org (eli.bendersky) Date: Fri, 15 Apr 2011 06:29:43 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): merge from 3.2 Message-ID: http://hg.python.org/cpython/rev/3ca13a65b90f changeset: 69353:3ca13a65b90f parent: 69350:7563f10275a2 parent: 69352:d8f8e20719b8 user: Eli Bendersky date: Fri Apr 15 07:29:31 2011 +0300 summary: merge from 3.2 files: Doc/library/subprocess.rst | 44 ++++++++++++++++++++++--- 1 files changed, 38 insertions(+), 6 deletions(-) diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst --- a/Doc/library/subprocess.rst +++ b/Doc/library/subprocess.rst @@ -94,12 +94,10 @@ *shell=False* does not suffer from this vulnerability; the above Note may be helpful in getting code using *shell=False* to work. - On Windows: the :class:`Popen` class uses CreateProcess() to execute the child - program, which operates on strings. If *args* is a sequence, it will be - converted to a string using the :meth:`list2cmdline` method. Please note that - not all MS Windows applications interpret the command line the same way: - :meth:`list2cmdline` is designed for applications using the same rules as the MS - C runtime. + On Windows: the :class:`Popen` class uses CreateProcess() to execute the + child program, which operates on strings. If *args* is a sequence, it will + be converted to a string in a manner described in + :ref:`converting-argument-sequence`. *bufsize*, if given, has the same meaning as the corresponding argument to the built-in open() function: :const:`0` means unbuffered, :const:`1` means line @@ -733,3 +731,37 @@ * popen2 closes all file descriptors by default, but you have to specify ``close_fds=True`` with :class:`Popen` to guarantee this behavior on all platforms or past Python versions. + +Notes +----- + +.. _converting-argument-sequence: + +Converting an argument sequence to a string on Windows +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +On Windows, an *args* sequence is converted to a string that can be parsed +using the following rules (which correspond to the rules used by the MS C +runtime): + +1. Arguments are delimited by white space, which is either a + space or a tab. + +2. A string surrounded by double quotation marks is + interpreted as a single argument, regardless of white space + contained within. A quoted string can be embedded in an + argument. + +3. A double quotation mark preceded by a backslash is + interpreted as a literal double quotation mark. + +4. Backslashes are interpreted literally, unless they + immediately precede a double quotation mark. + +5. If backslashes immediately precede a double quotation mark, + every pair of backslashes is interpreted as a literal + backslash. If the number of backslashes is odd, the last + backslash escapes the next double quotation mark as + described in rule 3. + + -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 15 06:35:02 2011 From: python-checkins at python.org (eli.bendersky) Date: Fri, 15 Apr 2011 06:35:02 +0200 Subject: [Python-checkins] cpython (2.7): Issue #11827: remove mention of list2cmdline in the doc of subprocess Message-ID: http://hg.python.org/cpython/rev/f38489a3394f changeset: 69354:f38489a3394f branch: 2.7 parent: 69347:9cfb90c883af user: Eli Bendersky date: Fri Apr 15 07:35:06 2011 +0300 summary: Issue #11827: remove mention of list2cmdline in the doc of subprocess files: Doc/library/subprocess.rst | 40 ++++++++++++++++++++++--- 1 files changed, 35 insertions(+), 5 deletions(-) diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst --- a/Doc/library/subprocess.rst +++ b/Doc/library/subprocess.rst @@ -100,11 +100,9 @@ helpful in getting code using *shell=False* to work. On Windows: the :class:`Popen` class uses CreateProcess() to execute the child - program, which operates on strings. If *args* is a sequence, it will be - converted to a string using the :meth:`list2cmdline` method. Please note that - not all MS Windows applications interpret the command line the same way: - :meth:`list2cmdline` is designed for applications using the same rules as the MS - C runtime. + child program, which operates on strings. If *args* is a sequence, it will + be converted to a string in a manner described in + :ref:`converting-argument-sequence`. *bufsize*, if given, has the same meaning as the corresponding argument to the built-in open() function: :const:`0` means unbuffered, :const:`1` means line @@ -616,3 +614,35 @@ * popen2 closes all file descriptors by default, but you have to specify ``close_fds=True`` with :class:`Popen`. +Notes +----- + +.. _converting-argument-sequence: + +Converting an argument sequence to a string on Windows +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +On Windows, an *args* sequence is converted to a string that can be parsed +using the following rules (which correspond to the rules used by the MS C +runtime): + +1. Arguments are delimited by white space, which is either a + space or a tab. + +2. A string surrounded by double quotation marks is + interpreted as a single argument, regardless of white space + contained within. A quoted string can be embedded in an + argument. + +3. A double quotation mark preceded by a backslash is + interpreted as a literal double quotation mark. + +4. Backslashes are interpreted literally, unless they + immediately precede a double quotation mark. + +5. If backslashes immediately precede a double quotation mark, + every pair of backslashes is interpreted as a literal + backslash. If the number of backslashes is odd, the last + backslash escapes the next double quotation mark as + described in rule 3. + -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 15 06:40:55 2011 From: python-checkins at python.org (ezio.melotti) Date: Fri, 15 Apr 2011 06:40:55 +0200 Subject: [Python-checkins] cpython (2.7): #4783: document that is not possible to use json.dump twice on the same stream. Message-ID: http://hg.python.org/cpython/rev/8dbf072556b9 changeset: 69355:8dbf072556b9 branch: 2.7 user: Ezio Melotti date: Fri Apr 15 07:37:00 2011 +0300 summary: #4783: document that is not possible to use json.dump twice on the same stream. files: Doc/library/json.rst | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-) diff --git a/Doc/library/json.rst b/Doc/library/json.rst --- a/Doc/library/json.rst +++ b/Doc/library/json.rst @@ -156,6 +156,11 @@ :meth:`default` method to serialize additional types), specify it with the *cls* kwarg; otherwise :class:`JSONEncoder` is used. + .. note:: + + Unlike :mod:`pickle` and :mod:`marshal`, JSON is not a framed protocol so + trying to serialize more objects with repeated calls to :func:`dump` and + the same *fp* will result in an invalid JSON file. .. function:: dumps(obj[, skipkeys[, ensure_ascii[, check_circular[, allow_nan[, cls[, indent[, separators[, encoding[, default[, **kw]]]]]]]]]]) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 15 06:40:55 2011 From: python-checkins at python.org (ezio.melotti) Date: Fri, 15 Apr 2011 06:40:55 +0200 Subject: [Python-checkins] cpython (3.1): #4783: document that is not possible to use json.dump twice on the same stream. Message-ID: http://hg.python.org/cpython/rev/2ec08aa2c566 changeset: 69356:2ec08aa2c566 branch: 3.1 parent: 69351:e7a55e236b8b user: Ezio Melotti date: Fri Apr 15 07:37:00 2011 +0300 summary: #4783: document that is not possible to use json.dump twice on the same stream. files: Doc/library/json.rst | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-) diff --git a/Doc/library/json.rst b/Doc/library/json.rst --- a/Doc/library/json.rst +++ b/Doc/library/json.rst @@ -156,6 +156,11 @@ Serialize *obj* to a JSON formatted :class:`str`. The arguments have the same meaning as in :func:`dump`. + .. note:: + + Unlike :mod:`pickle` and :mod:`marshal`, JSON is not a framed protocol so + trying to serialize more objects with repeated calls to :func:`dump` and + the same *fp* will result in an invalid JSON file. .. function:: load(fp, cls=None, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, object_pairs_hook=None, **kw) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 15 06:40:57 2011 From: python-checkins at python.org (ezio.melotti) Date: Fri, 15 Apr 2011 06:40:57 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): #4783: Merge with 3.1. Message-ID: http://hg.python.org/cpython/rev/1e315794ac8c changeset: 69357:1e315794ac8c branch: 3.2 parent: 69352:d8f8e20719b8 parent: 69356:2ec08aa2c566 user: Ezio Melotti date: Fri Apr 15 07:39:08 2011 +0300 summary: #4783: Merge with 3.1. files: Doc/library/json.rst | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-) diff --git a/Doc/library/json.rst b/Doc/library/json.rst --- a/Doc/library/json.rst +++ b/Doc/library/json.rst @@ -158,6 +158,11 @@ Serialize *obj* to a JSON formatted :class:`str`. The arguments have the same meaning as in :func:`dump`. + .. note:: + + Unlike :mod:`pickle` and :mod:`marshal`, JSON is not a framed protocol so + trying to serialize more objects with repeated calls to :func:`dump` and + the same *fp* will result in an invalid JSON file. .. function:: load(fp, cls=None, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, object_pairs_hook=None, **kw) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 15 06:40:58 2011 From: python-checkins at python.org (ezio.melotti) Date: Fri, 15 Apr 2011 06:40:58 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): #4783: Merge with 3.2. Message-ID: http://hg.python.org/cpython/rev/91881e304e13 changeset: 69358:91881e304e13 parent: 69353:3ca13a65b90f parent: 69357:1e315794ac8c user: Ezio Melotti date: Fri Apr 15 07:40:37 2011 +0300 summary: #4783: Merge with 3.2. files: Doc/library/json.rst | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-) diff --git a/Doc/library/json.rst b/Doc/library/json.rst --- a/Doc/library/json.rst +++ b/Doc/library/json.rst @@ -158,6 +158,11 @@ Serialize *obj* to a JSON formatted :class:`str`. The arguments have the same meaning as in :func:`dump`. + .. note:: + + Unlike :mod:`pickle` and :mod:`marshal`, JSON is not a framed protocol so + trying to serialize more objects with repeated calls to :func:`dump` and + the same *fp* will result in an invalid JSON file. .. function:: load(fp, cls=None, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, object_pairs_hook=None, **kw) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 15 07:19:44 2011 From: python-checkins at python.org (ezio.melotti) Date: Fri, 15 Apr 2011 07:19:44 +0200 Subject: [Python-checkins] cpython (3.2): #11845: Fix typo in rangeobject.c that caused a crash in compute_slice_indices. Message-ID: http://hg.python.org/cpython/rev/8025fb83dece changeset: 69359:8025fb83dece branch: 3.2 parent: 69357:1e315794ac8c user: Ezio Melotti date: Fri Apr 15 08:15:40 2011 +0300 summary: #11845: Fix typo in rangeobject.c that caused a crash in compute_slice_indices. Patch by Daniel Urban. files: Lib/test/test_range.py | 9 +++++++++ Misc/NEWS | 3 +++ Objects/rangeobject.c | 2 +- 3 files changed, 13 insertions(+), 1 deletions(-) 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 @@ -498,6 +498,15 @@ ]: self.assertEqual(list(reversed(r)), list(r)[::-1]) + def test_issue11845(self): + r = range(*slice(1, 18, 2).indices(20)) + values = {None, 0, 1, -1, 2, -2, 5, -5, 19, -19, + 20, -20, 21, -21, 30, -30, 99, -99} + for i in values: + for j in values: + for k in values - {0}: + r[i:j:k] + def test_main(): test.support.run_unittest(RangeTest) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #11845: Fix typo in rangeobject.c that caused a crash in + compute_slice_indices. Patch by Daniel Urban. + - Issue #11650: PyOS_StdioReadline() retries fgets() if it was interrupted (EINTR), for example if the program is stopped with CTRL+z on Mac OS X. Patch written by Charles-Francois Natali. diff --git a/Objects/rangeobject.c b/Objects/rangeobject.c --- a/Objects/rangeobject.c +++ b/Objects/rangeobject.c @@ -472,7 +472,7 @@ if (tmp_stop == NULL) goto Fail; } else { tmp_stop = r->length; - Py_INCREF(tmp_start); + Py_INCREF(tmp_stop); } } } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 15 07:19:44 2011 From: python-checkins at python.org (ezio.melotti) Date: Fri, 15 Apr 2011 07:19:44 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): #11845: Merge with 3.2. Message-ID: http://hg.python.org/cpython/rev/724e2e84a74f changeset: 69360:724e2e84a74f parent: 69358:91881e304e13 parent: 69359:8025fb83dece user: Ezio Melotti date: Fri Apr 15 08:19:32 2011 +0300 summary: #11845: Merge with 3.2. files: Lib/test/test_range.py | 9 +++++++++ Misc/NEWS | 3 +++ Objects/rangeobject.c | 2 +- 3 files changed, 13 insertions(+), 1 deletions(-) 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 @@ -498,6 +498,15 @@ ]: self.assertEqual(list(reversed(r)), list(r)[::-1]) + def test_issue11845(self): + r = range(*slice(1, 18, 2).indices(20)) + values = {None, 0, 1, -1, 2, -2, 5, -5, 19, -19, + 20, -20, 21, -21, 30, -30, 99, -99} + for i in values: + for j in values: + for k in values - {0}: + r[i:j:k] + def test_main(): test.support.run_unittest(RangeTest) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #11845: Fix typo in rangeobject.c that caused a crash in + compute_slice_indices. Patch by Daniel Urban. + - Issue #5673: Added a `timeout` keyword argument to subprocess.Popen.wait, subprocess.Popen.communicated, subprocess.call, subprocess.check_call, and subprocess.check_output. If the blocking operation takes more than `timeout` diff --git a/Objects/rangeobject.c b/Objects/rangeobject.c --- a/Objects/rangeobject.c +++ b/Objects/rangeobject.c @@ -472,7 +472,7 @@ if (tmp_stop == NULL) goto Fail; } else { tmp_stop = r->length; - Py_INCREF(tmp_start); + Py_INCREF(tmp_stop); } } } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 15 07:27:51 2011 From: python-checkins at python.org (ezio.melotti) Date: Fri, 15 Apr 2011 07:27:51 +0200 Subject: [Python-checkins] cpython (2.7): #11848: replace dead link in random.betavariate comment. Message-ID: http://hg.python.org/cpython/rev/e1f0881d2cb4 changeset: 69361:e1f0881d2cb4 branch: 2.7 parent: 69355:8dbf072556b9 user: Ezio Melotti date: Fri Apr 15 08:25:16 2011 +0300 summary: #11848: replace dead link in random.betavariate comment. files: Lib/random.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/random.py b/Lib/random.py --- a/Lib/random.py +++ b/Lib/random.py @@ -598,7 +598,7 @@ ## -------------------- beta -------------------- ## See -## http://sourceforge.net/bugs/?func=detailbug&bug_id=130030&group_id=5470 +## http://mail.python.org/pipermail/python-bugs-list/2001-January/003752.html ## for Ivan Frohne's insightful analysis of why the original implementation: ## ## def betavariate(self, alpha, beta): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 15 07:27:52 2011 From: python-checkins at python.org (ezio.melotti) Date: Fri, 15 Apr 2011 07:27:52 +0200 Subject: [Python-checkins] cpython (3.1): #11848: replace dead link in random.betavariate comment. Message-ID: http://hg.python.org/cpython/rev/f5b9ad73157c changeset: 69362:f5b9ad73157c branch: 3.1 parent: 69356:2ec08aa2c566 user: Ezio Melotti date: Fri Apr 15 08:25:16 2011 +0300 summary: #11848: replace dead link in random.betavariate comment. files: Lib/random.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/random.py b/Lib/random.py --- a/Lib/random.py +++ b/Lib/random.py @@ -578,7 +578,7 @@ ## -------------------- beta -------------------- ## See -## http://sourceforge.net/bugs/?func=detailbug&bug_id=130030&group_id=5470 +## http://mail.python.org/pipermail/python-bugs-list/2001-January/003752.html ## for Ivan Frohne's insightful analysis of why the original implementation: ## ## def betavariate(self, alpha, beta): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 15 07:27:53 2011 From: python-checkins at python.org (ezio.melotti) Date: Fri, 15 Apr 2011 07:27:53 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): #11848: Merge with 3.1. Message-ID: http://hg.python.org/cpython/rev/40656d8ae2c6 changeset: 69363:40656d8ae2c6 branch: 3.2 parent: 69359:8025fb83dece parent: 69362:f5b9ad73157c user: Ezio Melotti date: Fri Apr 15 08:27:00 2011 +0300 summary: #11848: Merge with 3.1. files: Lib/random.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/random.py b/Lib/random.py --- a/Lib/random.py +++ b/Lib/random.py @@ -573,7 +573,7 @@ ## -------------------- beta -------------------- ## See -## http://sourceforge.net/bugs/?func=detailbug&bug_id=130030&group_id=5470 +## http://mail.python.org/pipermail/python-bugs-list/2001-January/003752.html ## for Ivan Frohne's insightful analysis of why the original implementation: ## ## def betavariate(self, alpha, beta): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 15 07:27:56 2011 From: python-checkins at python.org (ezio.melotti) Date: Fri, 15 Apr 2011 07:27:56 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): #11848: Merge with 3.2. Message-ID: http://hg.python.org/cpython/rev/2acb16023fbe changeset: 69364:2acb16023fbe parent: 69360:724e2e84a74f parent: 69363:40656d8ae2c6 user: Ezio Melotti date: Fri Apr 15 08:27:37 2011 +0300 summary: #11848: Merge with 3.2. files: Lib/random.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/random.py b/Lib/random.py --- a/Lib/random.py +++ b/Lib/random.py @@ -573,7 +573,7 @@ ## -------------------- beta -------------------- ## See -## http://sourceforge.net/bugs/?func=detailbug&bug_id=130030&group_id=5470 +## http://mail.python.org/pipermail/python-bugs-list/2001-January/003752.html ## for Ivan Frohne's insightful analysis of why the original implementation: ## ## def betavariate(self, alpha, beta): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 15 12:08:32 2011 From: python-checkins at python.org (senthil.kumaran) Date: Fri, 15 Apr 2011 12:08:32 +0200 Subject: [Python-checkins] cpython (2.7): Issue #11467: Fix urlparse behavior when handling urls which contains scheme Message-ID: http://hg.python.org/cpython/rev/7a693e283c68 changeset: 69365:7a693e283c68 branch: 2.7 parent: 69361:e1f0881d2cb4 user: Senthil Kumaran date: Fri Apr 15 18:07:33 2011 +0800 summary: Issue #11467: Fix urlparse behavior when handling urls which contains scheme specific part only digits. Patch by Santoso Wijaya. files: Lib/test/test_urlparse.py | 7 +++++-- Lib/urlparse.py | 14 +++++++++----- Misc/NEWS | 3 +++ 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/Lib/test/test_urlparse.py b/Lib/test/test_urlparse.py --- a/Lib/test/test_urlparse.py +++ b/Lib/test/test_urlparse.py @@ -196,10 +196,13 @@ #self.checkJoin(RFC1808_BASE, 'http:g', 'http:g') #self.checkJoin(RFC1808_BASE, 'http:', 'http:') + def test_RFC2368(self): + # Issue 11467: path that starts with a number is not parsed correctly + self.assertEqual(urlparse.urlparse('mailto:1337 at example.org'), + ('mailto', '', '1337 at example.org', '', '', '')) + def test_RFC2396(self): # cases from RFC 2396 - - self.checkJoin(RFC2396_BASE, 'g:h', 'g:h') self.checkJoin(RFC2396_BASE, 'g', 'http://a/b/c/g') self.checkJoin(RFC2396_BASE, './g', 'http://a/b/c/g') diff --git a/Lib/urlparse.py b/Lib/urlparse.py --- a/Lib/urlparse.py +++ b/Lib/urlparse.py @@ -187,11 +187,15 @@ v = SplitResult(scheme, netloc, url, query, fragment) _parse_cache[key] = v return v - if url.endswith(':') or not url[i+1].isdigit(): - for c in url[:i]: - if c not in scheme_chars: - break - else: + for c in url[:i]: + if c not in scheme_chars: + break + else: + try: + # make sure "url" is not actually a port number (in which case + # "scheme" is really part of the path + _testportnum = int(url[i+1:]) + except ValueError: scheme, url = url[:i].lower(), url[i+1:] if url[:2] == '//': diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -51,6 +51,9 @@ Library ------- +- Issue #11467: Fix urlparse behavior when handling urls which contains scheme + specific part only digits. Patch by Santoso Wijaya. + - Issue #11474: Fix the bug with url2pathname() handling of '/C|/' on Windows. Patch by Santoso Wijaya. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 15 12:22:35 2011 From: python-checkins at python.org (senthil.kumaran) Date: Fri, 15 Apr 2011 12:22:35 +0200 Subject: [Python-checkins] cpython (3.1): Issue #11467: Fix urlparse behavior when handling urls which contains scheme Message-ID: http://hg.python.org/cpython/rev/495d12196487 changeset: 69366:495d12196487 branch: 3.1 parent: 69362:f5b9ad73157c user: Senthil Kumaran date: Fri Apr 15 18:20:24 2011 +0800 summary: Issue #11467: Fix urlparse behavior when handling urls which contains scheme specific part only digits. files: Lib/test/test_urlparse.py | 5 +++++ Lib/urllib/parse.py | 15 ++++++++++----- Misc/NEWS | 3 +++ 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_urlparse.py b/Lib/test/test_urlparse.py --- a/Lib/test/test_urlparse.py +++ b/Lib/test/test_urlparse.py @@ -197,6 +197,11 @@ #self.checkJoin(RFC1808_BASE, 'http:g', 'http:g') #self.checkJoin(RFC1808_BASE, 'http:', 'http:') + def test_RFC2368(self): + # Issue 11467: path that starts with a number is not parsed correctly + self.assertEqual(urllib.parse.urlparse('mailto:1337 at example.org'), + ('mailto', '', '1337 at example.org', '', '', '')) + def test_RFC2396(self): # cases from RFC 2396 self.checkJoin(RFC2396_BASE, 'g:h', 'g:h') diff --git a/Lib/urllib/parse.py b/Lib/urllib/parse.py --- a/Lib/urllib/parse.py +++ b/Lib/urllib/parse.py @@ -184,12 +184,17 @@ v = SplitResult(scheme, netloc, url, query, fragment) _parse_cache[key] = v return v - if url.endswith(':') or not url[i+1].isdigit(): - for c in url[:i]: - if c not in scheme_chars: - break - else: + for c in url[:i]: + if c not in scheme_chars: + break + else: + try: + # make sure "url" is not actually a port number (in which case + # "scheme" is really part of the path + _testportnum = int(url[i+1:]) + except ValueError: scheme, url = url[:i].lower(), url[i+1:] + if url[:2] == '//': netloc, url = _splitnetloc(url, 2) if allow_fragments and scheme in uses_fragment and '#' in url: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -51,6 +51,9 @@ Library ------- +- Issue #11467: Fix urlparse behavior when handling urls which contains scheme + specific part only digits. Patch by Santoso Wijaya. + - Issue #11474: Fix the bug with url2pathname() handling of '/C|/' on Windows. Patch by Santoso Wijaya. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 15 12:22:35 2011 From: python-checkins at python.org (senthil.kumaran) Date: Fri, 15 Apr 2011 12:22:35 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): merge from 3.1 Message-ID: http://hg.python.org/cpython/rev/5423aaefadbb changeset: 69367:5423aaefadbb branch: 3.2 parent: 69363:40656d8ae2c6 parent: 69366:495d12196487 user: Senthil Kumaran date: Fri Apr 15 18:21:26 2011 +0800 summary: merge from 3.1 files: Lib/test/test_urlparse.py | 5 +++++ Lib/urllib/parse.py | 15 ++++++++++----- Misc/NEWS | 3 +++ 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_urlparse.py b/Lib/test/test_urlparse.py --- a/Lib/test/test_urlparse.py +++ b/Lib/test/test_urlparse.py @@ -228,6 +228,11 @@ #self.checkJoin(RFC1808_BASE, 'http:g', 'http:g') #self.checkJoin(RFC1808_BASE, 'http:', 'http:') + def test_RFC2368(self): + # Issue 11467: path that starts with a number is not parsed correctly + self.assertEqual(urllib.parse.urlparse('mailto:1337 at example.org'), + ('mailto', '', '1337 at example.org', '', '', '')) + def test_RFC2396(self): # cases from RFC 2396 diff --git a/Lib/urllib/parse.py b/Lib/urllib/parse.py --- a/Lib/urllib/parse.py +++ b/Lib/urllib/parse.py @@ -340,12 +340,17 @@ v = SplitResult(scheme, netloc, url, query, fragment) _parse_cache[key] = v return _coerce_result(v) - if url.endswith(':') or not url[i+1].isdigit(): - for c in url[:i]: - if c not in scheme_chars: - break - else: + for c in url[:i]: + if c not in scheme_chars: + break + else: + try: + # make sure "url" is not actually a port number (in which case + # "scheme" is really part of the path + _testportnum = int(url[i+1:]) + except ValueError: scheme, url = url[:i].lower(), url[i+1:] + if url[:2] == '//': netloc, url = _splitnetloc(url, 2) if (('[' in netloc and ']' not in netloc) or diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -56,6 +56,9 @@ Library ------- +- Issue #11467: Fix urlparse behavior when handling urls which contains scheme + specific part only digits. Patch by Santoso Wijaya. + - Issue #11474: Fix the bug with url2pathname() handling of '/C|/' on Windows. Patch by Santoso Wijaya. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 15 12:22:36 2011 From: python-checkins at python.org (senthil.kumaran) Date: Fri, 15 Apr 2011 12:22:36 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): merge from 3.2 Message-ID: http://hg.python.org/cpython/rev/febe57ec7053 changeset: 69368:febe57ec7053 parent: 69364:2acb16023fbe parent: 69367:5423aaefadbb user: Senthil Kumaran date: Fri Apr 15 18:22:05 2011 +0800 summary: merge from 3.2 files: Lib/test/test_urlparse.py | 5 +++++ Lib/urllib/parse.py | 15 ++++++++++----- Misc/NEWS | 3 +++ 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_urlparse.py b/Lib/test/test_urlparse.py --- a/Lib/test/test_urlparse.py +++ b/Lib/test/test_urlparse.py @@ -228,6 +228,11 @@ #self.checkJoin(RFC1808_BASE, 'http:g', 'http:g') #self.checkJoin(RFC1808_BASE, 'http:', 'http:') + def test_RFC2368(self): + # Issue 11467: path that starts with a number is not parsed correctly + self.assertEqual(urllib.parse.urlparse('mailto:1337 at example.org'), + ('mailto', '', '1337 at example.org', '', '', '')) + def test_RFC2396(self): # cases from RFC 2396 diff --git a/Lib/urllib/parse.py b/Lib/urllib/parse.py --- a/Lib/urllib/parse.py +++ b/Lib/urllib/parse.py @@ -340,12 +340,17 @@ v = SplitResult(scheme, netloc, url, query, fragment) _parse_cache[key] = v return _coerce_result(v) - if url.endswith(':') or not url[i+1].isdigit(): - for c in url[:i]: - if c not in scheme_chars: - break - else: + for c in url[:i]: + if c not in scheme_chars: + break + else: + try: + # make sure "url" is not actually a port number (in which case + # "scheme" is really part of the path + _testportnum = int(url[i+1:]) + except ValueError: scheme, url = url[:i].lower(), url[i+1:] + if url[:2] == '//': netloc, url = _splitnetloc(url, 2) if (('[' in netloc and ']' not in netloc) or diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -106,6 +106,9 @@ Library ------- +- Issue #11467: Fix urlparse behavior when handling urls which contains scheme + specific part only digits. Patch by Santoso Wijaya. + - Issue #11474: Fix the bug with url2pathname() handling of '/C|/' on Windows. Patch by Santoso Wijaya. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 15 15:53:01 2011 From: python-checkins at python.org (ezio.melotti) Date: Fri, 15 Apr 2011 15:53:01 +0200 Subject: [Python-checkins] cpython (2.7): Issue #5057: fix a bug in the peepholer that led to non-portable pyc files Message-ID: http://hg.python.org/cpython/rev/3cffa2009a92 changeset: 69369:3cffa2009a92 branch: 2.7 parent: 69365:7a693e283c68 user: Ezio Melotti date: Fri Apr 15 16:14:04 2011 +0300 summary: Issue #5057: fix a bug in the peepholer that led to non-portable pyc files between narrow and wide builds while optimizing BINARY_SUBSCR on non-BMP chars (e.g. u"\U00012345"[0]). files: Lib/test/test_peepholer.py | 18 ++++++++++++++++++ Misc/NEWS | 4 ++++ Python/peephole.c | 18 ++++++++++++++++++ 3 files changed, 40 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_peepholer.py b/Lib/test/test_peepholer.py --- a/Lib/test/test_peepholer.py +++ b/Lib/test/test_peepholer.py @@ -137,6 +137,24 @@ asm = dis_single('a="x"*1000') self.assertIn('(1000)', asm) + def test_binary_subscr_on_unicode(self): + # valid code get optimized + asm = dis_single('u"foo"[0]') + self.assertIn("(u'f')", asm) + self.assertNotIn('BINARY_SUBSCR', asm) + asm = dis_single('u"\u0061\uffff"[1]') + self.assertIn("(u'\\uffff')", asm) + self.assertNotIn('BINARY_SUBSCR', asm) + + # invalid code doesn't get optimized + # out of range + asm = dis_single('u"fuu"[10]') + self.assertIn('BINARY_SUBSCR', asm) + # non-BMP char (see #5057) + asm = dis_single('u"\U00012345"[0]') + self.assertIn('BINARY_SUBSCR', asm) + + def test_folding_of_unaryops_on_constants(self): for line, elem in ( ('`1`', "('1')"), # unary convert diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -9,6 +9,10 @@ Core and Builtins ----------------- +- Issue #5057: fix a bug in the peepholer that led to non-portable pyc files + between narrow and wide builds while optimizing BINARY_SUBSCR on non-BMP + chars (e.g. u"\U00012345"[0]). + - Issue #11650: PyOS_StdioReadline() retries fgets() if it was interrupted (EINTR), for example if the program is stopped with CTRL+z on Mac OS X. Patch written by Charles-Francois Natali. diff --git a/Python/peephole.c b/Python/peephole.c --- a/Python/peephole.c +++ b/Python/peephole.c @@ -129,6 +129,24 @@ break; case BINARY_SUBSCR: newconst = PyObject_GetItem(v, w); + /* #5057: if v is unicode, there might be differences between + wide and narrow builds in cases like u'\U00012345'[0]. + Wide builds will return a non-BMP char, whereas narrow builds + will return a surrogate. In both the cases skip the + optimization in order to produce compatible pycs. + */ + if (newconst != NULL && + PyUnicode_Check(v) && PyUnicode_Check(newconst)) { + Py_UNICODE ch = PyUnicode_AS_UNICODE(newconst)[0]; +#ifdef Py_UNICODE_WIDE + if (ch > 0xFFFF) { +#else + if (ch >= 0xD800 && ch <= 0xDFFF) { +#endif + Py_DECREF(newconst); + return 0; + } + } break; case BINARY_LSHIFT: newconst = PyNumber_Lshift(v, w); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 15 15:53:02 2011 From: python-checkins at python.org (ezio.melotti) Date: Fri, 15 Apr 2011 15:53:02 +0200 Subject: [Python-checkins] cpython (3.1): Issue #5057: fix a bug in the peepholer that led to non-portable pyc files Message-ID: http://hg.python.org/cpython/rev/4679d0fef389 changeset: 69370:4679d0fef389 branch: 3.1 parent: 69366:495d12196487 user: Ezio Melotti date: Fri Apr 15 16:38:34 2011 +0300 summary: Issue #5057: fix a bug in the peepholer that led to non-portable pyc files between narrow and wide builds while optimizing BINARY_SUBSCR on non-BMP chars (e.g. "\U00012345"[0]). files: Lib/test/test_peepholer.py | 18 ++++++++++++++++++ Misc/NEWS | 6 +++++- Python/peephole.c | 18 ++++++++++++++++++ 3 files changed, 41 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_peepholer.py b/Lib/test/test_peepholer.py --- a/Lib/test/test_peepholer.py +++ b/Lib/test/test_peepholer.py @@ -146,6 +146,24 @@ asm = dis_single('a="x"*1000') self.assertTrue('(1000)' in asm) + def test_binary_subscr_on_unicode(self): + # valid code get optimized + asm = dis_single('"foo"[0]') + self.assertIn("('f')", asm) + self.assertNotIn('BINARY_SUBSCR', asm) + asm = dis_single('"\u0061\uffff"[1]') + self.assertIn("('\\uffff')", asm) + self.assertNotIn('BINARY_SUBSCR', asm) + + # invalid code doesn't get optimized + # out of range + asm = dis_single('"fuu"[10]') + self.assertIn('BINARY_SUBSCR', asm) + # non-BMP char (see #5057) + asm = dis_single('"\U00012345"[0]') + self.assertIn('BINARY_SUBSCR', asm) + + def test_folding_of_unaryops_on_constants(self): for line, elem in ( ('-0.5', '(-0.5)'), # unary negative diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,10 @@ Core and Builtins ----------------- +- Issue #5057: fix a bug in the peepholer that led to non-portable pyc files + between narrow and wide builds while optimizing BINARY_SUBSCR on non-BMP + chars (e.g. "\U00012345"[0]). + - Issue #11650: PyOS_StdioReadline() retries fgets() if it was interrupted (EINTR), for example if the program is stopped with CTRL+z on Mac OS X. Patch written by Charles-Francois Natali. @@ -51,7 +55,7 @@ Library ------- -- Issue #11467: Fix urlparse behavior when handling urls which contains scheme +- Issue #11467: Fix urlparse behavior when handling urls which contains scheme specific part only digits. Patch by Santoso Wijaya. - Issue #11474: Fix the bug with url2pathname() handling of '/C|/' on Windows. diff --git a/Python/peephole.c b/Python/peephole.c --- a/Python/peephole.c +++ b/Python/peephole.c @@ -124,6 +124,24 @@ break; case BINARY_SUBSCR: newconst = PyObject_GetItem(v, w); + /* #5057: if v is unicode, there might be differences between + wide and narrow builds in cases like '\U00012345'[0]. + Wide builds will return a non-BMP char, whereas narrow builds + will return a surrogate. In both the cases skip the + optimization in order to produce compatible pycs. + */ + if (newconst != NULL && + PyUnicode_Check(v) && PyUnicode_Check(newconst)) { + Py_UNICODE ch = PyUnicode_AS_UNICODE(newconst)[0]; +#ifdef Py_UNICODE_WIDE + if (ch > 0xFFFF) { +#else + if (ch >= 0xD800 && ch <= 0xDFFF) { +#endif + Py_DECREF(newconst); + return 0; + } + } break; case BINARY_LSHIFT: newconst = PyNumber_Lshift(v, w); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 15 15:53:06 2011 From: python-checkins at python.org (ezio.melotti) Date: Fri, 15 Apr 2011 15:53:06 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): #5057: Merge with 3.1. Message-ID: http://hg.python.org/cpython/rev/503578ddf286 changeset: 69371:503578ddf286 branch: 3.2 parent: 69367:5423aaefadbb parent: 69370:4679d0fef389 user: Ezio Melotti date: Fri Apr 15 16:50:41 2011 +0300 summary: #5057: Merge with 3.1. files: Lib/test/test_peepholer.py | 18 ++++++++++++++++++ Misc/NEWS | 6 +++++- Python/peephole.c | 18 ++++++++++++++++++ 3 files changed, 41 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_peepholer.py b/Lib/test/test_peepholer.py --- a/Lib/test/test_peepholer.py +++ b/Lib/test/test_peepholer.py @@ -195,6 +195,24 @@ asm = dis_single('a="x"*1000') self.assertIn('(1000)', asm) + def test_binary_subscr_on_unicode(self): + # valid code get optimized + asm = dis_single('"foo"[0]') + self.assertIn("('f')", asm) + self.assertNotIn('BINARY_SUBSCR', asm) + asm = dis_single('"\u0061\uffff"[1]') + self.assertIn("('\\uffff')", asm) + self.assertNotIn('BINARY_SUBSCR', asm) + + # invalid code doesn't get optimized + # out of range + asm = dis_single('"fuu"[10]') + self.assertIn('BINARY_SUBSCR', asm) + # non-BMP char (see #5057) + asm = dis_single('"\U00012345"[0]') + self.assertIn('BINARY_SUBSCR', asm) + + def test_folding_of_unaryops_on_constants(self): for line, elem in ( ('-0.5', '(-0.5)'), # unary negative diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,10 @@ Core and Builtins ----------------- +- Issue #5057: fix a bug in the peepholer that led to non-portable pyc files + between narrow and wide builds while optimizing BINARY_SUBSCR on non-BMP + chars (e.g. "\U00012345"[0]). + - Issue #11845: Fix typo in rangeobject.c that caused a crash in compute_slice_indices. Patch by Daniel Urban. @@ -56,7 +60,7 @@ Library ------- -- Issue #11467: Fix urlparse behavior when handling urls which contains scheme +- Issue #11467: Fix urlparse behavior when handling urls which contains scheme specific part only digits. Patch by Santoso Wijaya. - Issue #11474: Fix the bug with url2pathname() handling of '/C|/' on Windows. diff --git a/Python/peephole.c b/Python/peephole.c --- a/Python/peephole.c +++ b/Python/peephole.c @@ -133,6 +133,24 @@ break; case BINARY_SUBSCR: newconst = PyObject_GetItem(v, w); + /* #5057: if v is unicode, there might be differences between + wide and narrow builds in cases like '\U00012345'[0]. + Wide builds will return a non-BMP char, whereas narrow builds + will return a surrogate. In both the cases skip the + optimization in order to produce compatible pycs. + */ + if (newconst != NULL && + PyUnicode_Check(v) && PyUnicode_Check(newconst)) { + Py_UNICODE ch = PyUnicode_AS_UNICODE(newconst)[0]; +#ifdef Py_UNICODE_WIDE + if (ch > 0xFFFF) { +#else + if (ch >= 0xD800 && ch <= 0xDFFF) { +#endif + Py_DECREF(newconst); + return 0; + } + } break; case BINARY_LSHIFT: newconst = PyNumber_Lshift(v, w); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 15 15:53:08 2011 From: python-checkins at python.org (ezio.melotti) Date: Fri, 15 Apr 2011 15:53:08 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): #5057: Merge with 3.2. Message-ID: http://hg.python.org/cpython/rev/9801e1f78264 changeset: 69372:9801e1f78264 parent: 69368:febe57ec7053 parent: 69371:503578ddf286 user: Ezio Melotti date: Fri Apr 15 16:52:35 2011 +0300 summary: #5057: Merge with 3.2. files: Lib/test/test_peepholer.py | 18 ++++++++++++++++++ Misc/NEWS | 6 +++++- Python/peephole.c | 18 ++++++++++++++++++ 3 files changed, 41 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_peepholer.py b/Lib/test/test_peepholer.py --- a/Lib/test/test_peepholer.py +++ b/Lib/test/test_peepholer.py @@ -205,6 +205,24 @@ asm = dis_single('a="x"*1000') self.assertIn('(1000)', asm) + def test_binary_subscr_on_unicode(self): + # valid code get optimized + asm = dis_single('"foo"[0]') + self.assertIn("('f')", asm) + self.assertNotIn('BINARY_SUBSCR', asm) + asm = dis_single('"\u0061\uffff"[1]') + self.assertIn("('\\uffff')", asm) + self.assertNotIn('BINARY_SUBSCR', asm) + + # invalid code doesn't get optimized + # out of range + asm = dis_single('"fuu"[10]') + self.assertIn('BINARY_SUBSCR', asm) + # non-BMP char (see #5057) + asm = dis_single('"\U00012345"[0]') + self.assertIn('BINARY_SUBSCR', asm) + + def test_folding_of_unaryops_on_constants(self): for line, elem in ( ('-0.5', '(-0.5)'), # unary negative diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,10 @@ Core and Builtins ----------------- +- Issue #5057: fix a bug in the peepholer that led to non-portable pyc files + between narrow and wide builds while optimizing BINARY_SUBSCR on non-BMP + chars (e.g. "\U00012345"[0]). + - Issue #11845: Fix typo in rangeobject.c that caused a crash in compute_slice_indices. Patch by Daniel Urban. @@ -106,7 +110,7 @@ Library ------- -- Issue #11467: Fix urlparse behavior when handling urls which contains scheme +- Issue #11467: Fix urlparse behavior when handling urls which contains scheme specific part only digits. Patch by Santoso Wijaya. - Issue #11474: Fix the bug with url2pathname() handling of '/C|/' on Windows. diff --git a/Python/peephole.c b/Python/peephole.c --- a/Python/peephole.c +++ b/Python/peephole.c @@ -183,6 +183,24 @@ break; case BINARY_SUBSCR: newconst = PyObject_GetItem(v, w); + /* #5057: if v is unicode, there might be differences between + wide and narrow builds in cases like '\U00012345'[0]. + Wide builds will return a non-BMP char, whereas narrow builds + will return a surrogate. In both the cases skip the + optimization in order to produce compatible pycs. + */ + if (newconst != NULL && + PyUnicode_Check(v) && PyUnicode_Check(newconst)) { + Py_UNICODE ch = PyUnicode_AS_UNICODE(newconst)[0]; +#ifdef Py_UNICODE_WIDE + if (ch > 0xFFFF) { +#else + if (ch >= 0xD800 && ch <= 0xDFFF) { +#endif + Py_DECREF(newconst); + return 0; + } + } break; case BINARY_LSHIFT: newconst = PyNumber_Lshift(v, w); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 15 17:08:25 2011 From: python-checkins at python.org (ezio.melotti) Date: Fri, 15 Apr 2011 17:08:25 +0200 Subject: [Python-checkins] cpython (2.7): #11843: remove duplicate line from table in distutil doc. Message-ID: http://hg.python.org/cpython/rev/9e49f4d81f54 changeset: 69373:9e49f4d81f54 branch: 2.7 parent: 69369:3cffa2009a92 user: Ezio Melotti date: Fri Apr 15 18:05:09 2011 +0300 summary: #11843: remove duplicate line from table in distutil doc. files: Doc/distutils/builtdist.rst | 2 -- 1 files changed, 0 insertions(+), 2 deletions(-) diff --git a/Doc/distutils/builtdist.rst b/Doc/distutils/builtdist.rst --- a/Doc/distutils/builtdist.rst +++ b/Doc/distutils/builtdist.rst @@ -88,8 +88,6 @@ +-------------+------------------------------+---------+ | ``sdux`` | HP-UX :program:`swinstall` | | +-------------+------------------------------+---------+ -| ``rpm`` | RPM | \(5) | -+-------------+------------------------------+---------+ | ``wininst`` | self-extracting ZIP file for | \(4) | | | Windows | | +-------------+------------------------------+---------+ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 15 17:08:27 2011 From: python-checkins at python.org (ezio.melotti) Date: Fri, 15 Apr 2011 17:08:27 +0200 Subject: [Python-checkins] cpython (3.1): #11843: remove duplicate line from table in distutil doc. Message-ID: http://hg.python.org/cpython/rev/1d6e28df2fb7 changeset: 69374:1d6e28df2fb7 branch: 3.1 parent: 69370:4679d0fef389 user: Ezio Melotti date: Fri Apr 15 18:05:09 2011 +0300 summary: #11843: remove duplicate line from table in distutil doc. files: Doc/distutils/builtdist.rst | 2 -- 1 files changed, 0 insertions(+), 2 deletions(-) diff --git a/Doc/distutils/builtdist.rst b/Doc/distutils/builtdist.rst --- a/Doc/distutils/builtdist.rst +++ b/Doc/distutils/builtdist.rst @@ -88,8 +88,6 @@ +-------------+------------------------------+---------+ | ``sdux`` | HP-UX :program:`swinstall` | | +-------------+------------------------------+---------+ -| ``rpm`` | RPM | \(5) | -+-------------+------------------------------+---------+ | ``wininst`` | self-extracting ZIP file for | \(4) | | | Windows | | +-------------+------------------------------+---------+ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 15 17:08:30 2011 From: python-checkins at python.org (ezio.melotti) Date: Fri, 15 Apr 2011 17:08:30 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): #11843: Merge with 3.1. Message-ID: http://hg.python.org/cpython/rev/850a659d9e6f changeset: 69375:850a659d9e6f branch: 3.2 parent: 69371:503578ddf286 parent: 69374:1d6e28df2fb7 user: Ezio Melotti date: Fri Apr 15 18:07:38 2011 +0300 summary: #11843: Merge with 3.1. files: Doc/distutils/builtdist.rst | 2 -- 1 files changed, 0 insertions(+), 2 deletions(-) diff --git a/Doc/distutils/builtdist.rst b/Doc/distutils/builtdist.rst --- a/Doc/distutils/builtdist.rst +++ b/Doc/distutils/builtdist.rst @@ -88,8 +88,6 @@ +-------------+------------------------------+---------+ | ``sdux`` | HP-UX :program:`swinstall` | | +-------------+------------------------------+---------+ -| ``rpm`` | RPM | \(5) | -+-------------+------------------------------+---------+ | ``wininst`` | self-extracting ZIP file for | \(4) | | | Windows | | +-------------+------------------------------+---------+ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 15 17:08:34 2011 From: python-checkins at python.org (ezio.melotti) Date: Fri, 15 Apr 2011 17:08:34 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): #11843: Merge with 3.2. Message-ID: http://hg.python.org/cpython/rev/bf1bf8fb5d55 changeset: 69376:bf1bf8fb5d55 parent: 69372:9801e1f78264 parent: 69375:850a659d9e6f user: Ezio Melotti date: Fri Apr 15 18:08:09 2011 +0300 summary: #11843: Merge with 3.2. files: Doc/distutils/builtdist.rst | 2 -- 1 files changed, 0 insertions(+), 2 deletions(-) diff --git a/Doc/distutils/builtdist.rst b/Doc/distutils/builtdist.rst --- a/Doc/distutils/builtdist.rst +++ b/Doc/distutils/builtdist.rst @@ -88,8 +88,6 @@ +-------------+------------------------------+---------+ | ``sdux`` | HP-UX :program:`swinstall` | | +-------------+------------------------------+---------+ -| ``rpm`` | RPM | \(5) | -+-------------+------------------------------+---------+ | ``wininst`` | self-extracting ZIP file for | \(4) | | | Windows | | +-------------+------------------------------+---------+ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 15 19:39:18 2011 From: python-checkins at python.org (nick.coghlan) Date: Fri, 15 Apr 2011 19:39:18 +0200 Subject: [Python-checkins] peps: Give Deferred PEPs their own section in PEP 0 Message-ID: http://hg.python.org/peps/rev/e87b26c21dcb changeset: 3868:e87b26c21dcb user: Nick Coghlan date: Sat Apr 16 03:39:10 2011 +1000 summary: Give Deferred PEPs their own section in PEP 0 files: pep0/output.py | 19 ++++++++++++++----- 1 files changed, 14 insertions(+), 5 deletions(-) diff --git a/pep0/output.py b/pep0/output.py --- a/pep0/output.py +++ b/pep0/output.py @@ -31,6 +31,7 @@ open_ = [] finished = [] historical = [] + deferred = [] dead = [] for pep in peps: # Order of 'if' statement important. Key Status values take precedence @@ -44,8 +45,10 @@ historical.append(pep) elif pep.status == 'Draft': open_.append(pep) - elif pep.status in ('Rejected', 'Withdrawn', 'Deferred', - 'Incomplete', 'Superseded'): + elif pep.status == 'Deferred': + deferred.append(pep) + elif pep.status in ('Rejected', 'Withdrawn', + 'Incomplete', 'Superseded'): dead.append(pep) elif pep.type_ == 'Informational': # Hack until the conflict between the use of "Final" @@ -64,7 +67,7 @@ raise PEPError("unsorted (%s/%s)" % (pep.type_, pep.status), pep.filename, pep.number) - return meta, info, accepted, open_, finished, historical, dead + return meta, info, accepted, open_, finished, historical, deferred, dead def verify_email_addresses(peps): @@ -122,7 +125,8 @@ print>>output, u"Index by Category" print>>output write_column_headers(output) - meta, info, accepted, open_, finished, historical, dead = sort_peps(peps) + (meta, info, accepted, open_, finished, + historical, deferred, dead) = sort_peps(peps) print>>output print>>output, u" Meta-PEPs (PEPs about PEPs or Processes)" print>>output @@ -154,7 +158,12 @@ for pep in historical: print>>output, unicode(pep) print>>output - print>>output, u" Deferred, Abandoned, Withdrawn, and Rejected PEPs" + print>>output, u" Deferred PEPs" + print>>output + for pep in deferred: + print>>output, unicode(pep) + print>>output + print>>output, u" Abandoned, Withdrawn, and Rejected PEPs" print>>output for pep in dead: print>>output, unicode(pep) -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Fri Apr 15 21:03:04 2011 From: python-checkins at python.org (r.david.murray) Date: Fri, 15 Apr 2011 21:03:04 +0200 Subject: [Python-checkins] cpython: Remove unused method from internal class. Message-ID: http://hg.python.org/cpython/rev/51ebdd888a43 changeset: 69377:51ebdd888a43 user: R David Murray date: Fri Apr 15 14:55:04 2011 -0400 summary: Remove unused method from internal class. files: Lib/email/feedparser.py | 3 --- 1 files changed, 0 insertions(+), 3 deletions(-) diff --git a/Lib/email/feedparser.py b/Lib/email/feedparser.py --- a/Lib/email/feedparser.py +++ b/Lib/email/feedparser.py @@ -120,9 +120,6 @@ # Reverse and insert at the front of the lines. self._lines[:0] = lines[::-1] - def is_closed(self): - return self._closed - def __iter__(self): return self -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 15 22:15:37 2011 From: python-checkins at python.org (raymond.hettinger) Date: Fri, 15 Apr 2011 22:15:37 +0200 Subject: [Python-checkins] cpython (2.7): Fix minor subclassing issue with collections.Counter Message-ID: http://hg.python.org/cpython/rev/30d6bc10e862 changeset: 69378:30d6bc10e862 branch: 2.7 parent: 69373:9e49f4d81f54 user: Raymond Hettinger date: Fri Apr 15 13:12:21 2011 -0700 summary: Fix minor subclassing issue with collections.Counter files: Lib/collections.py | 4 ++-- Lib/test/test_collections.py | 9 +++++++++ Misc/NEWS | 2 ++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/Lib/collections.py b/Lib/collections.py --- a/Lib/collections.py +++ b/Lib/collections.py @@ -516,8 +516,8 @@ self.subtract(kwds) def copy(self): - 'Like dict.copy() but returns a Counter instance instead of a dict.' - return Counter(self) + 'Return a shallow copy.' + return self.__class__(self) def __reduce__(self): return self.__class__, (dict(self),) diff --git a/Lib/test/test_collections.py b/Lib/test/test_collections.py --- a/Lib/test/test_collections.py +++ b/Lib/test/test_collections.py @@ -689,6 +689,15 @@ self.assertEqual(len(dup), len(words)) self.assertEqual(type(dup), type(words)) + def test_copy_subclass(self): + class MyCounter(Counter): + pass + c = MyCounter('slartibartfast') + d = c.copy() + self.assertEqual(d, c) + self.assertEqual(len(d), len(c)) + self.assertEqual(type(d), type(c)) + def test_conversions(self): # Convert to: set, list, dict s = 'she sells sea shells by the sea shore' diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -58,6 +58,8 @@ - Issue #11467: Fix urlparse behavior when handling urls which contains scheme specific part only digits. Patch by Santoso Wijaya. +- collections.Counter().copy() now works correctly for subclasses. + - Issue #11474: Fix the bug with url2pathname() handling of '/C|/' on Windows. Patch by Santoso Wijaya. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 15 22:23:19 2011 From: python-checkins at python.org (raymond.hettinger) Date: Fri, 15 Apr 2011 22:23:19 +0200 Subject: [Python-checkins] cpython (3.1): Fix minor subclassing issue with collections.Counter Message-ID: http://hg.python.org/cpython/rev/a164f67d27be changeset: 69379:a164f67d27be branch: 3.1 parent: 69374:1d6e28df2fb7 user: Raymond Hettinger date: Fri Apr 15 13:16:46 2011 -0700 summary: Fix minor subclassing issue with collections.Counter files: Lib/collections.py | 4 ++-- Lib/test/test_collections.py | 9 +++++++++ Misc/NEWS | 2 ++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/Lib/collections.py b/Lib/collections.py --- a/Lib/collections.py +++ b/Lib/collections.py @@ -459,8 +459,8 @@ self.update(kwds) def copy(self): - 'Like dict.copy() but returns a Counter instance instead of a dict.' - return Counter(self) + 'Return a shallow copy.' + return self.__class__(self) def __reduce__(self): return self.__class__, (dict(self),) diff --git a/Lib/test/test_collections.py b/Lib/test/test_collections.py --- a/Lib/test/test_collections.py +++ b/Lib/test/test_collections.py @@ -680,6 +680,15 @@ self.assertEqual(len(dup), len(words)) self.assertEqual(type(dup), type(words)) + def test_copy_subclass(self): + class MyCounter(Counter): + pass + c = MyCounter('slartibartfast') + d = c.copy() + self.assertEqual(d, c) + self.assertEqual(len(d), len(c)) + self.assertEqual(type(d), type(c)) + def test_conversions(self): # Convert to: set, list, dict s = 'she sells sea shells by the sea shore' diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -58,6 +58,8 @@ - Issue #11467: Fix urlparse behavior when handling urls which contains scheme specific part only digits. Patch by Santoso Wijaya. +- collections.Counter().copy() now works correctly for subclasses. + - Issue #11474: Fix the bug with url2pathname() handling of '/C|/' on Windows. Patch by Santoso Wijaya. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 15 22:23:21 2011 From: python-checkins at python.org (raymond.hettinger) Date: Fri, 15 Apr 2011 22:23:21 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): Fix minor subclassing issue with collections.Counter Message-ID: http://hg.python.org/cpython/rev/bb13260d56c6 changeset: 69380:bb13260d56c6 branch: 3.2 parent: 69375:850a659d9e6f parent: 69379:a164f67d27be user: Raymond Hettinger date: Fri Apr 15 13:21:30 2011 -0700 summary: Fix minor subclassing issue with collections.Counter files: Lib/collections.py | 4 ++-- Lib/test/test_collections.py | 9 +++++++++ Misc/NEWS | 2 ++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/Lib/collections.py b/Lib/collections.py --- a/Lib/collections.py +++ b/Lib/collections.py @@ -536,8 +536,8 @@ self.subtract(kwds) def copy(self): - 'Like dict.copy() but returns a Counter instance instead of a dict.' - return Counter(self) + 'Return a shallow copy.' + return self.__class__(self) def __reduce__(self): return self.__class__, (dict(self),) diff --git a/Lib/test/test_collections.py b/Lib/test/test_collections.py --- a/Lib/test/test_collections.py +++ b/Lib/test/test_collections.py @@ -812,6 +812,15 @@ self.assertEqual(len(dup), len(words)) self.assertEqual(type(dup), type(words)) + def test_copy_subclass(self): + class MyCounter(Counter): + pass + c = MyCounter('slartibartfast') + d = c.copy() + self.assertEqual(d, c) + self.assertEqual(len(d), len(c)) + self.assertEqual(type(d), type(c)) + def test_conversions(self): # Convert to: set, list, dict s = 'she sells sea shells by the sea shore' diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -63,6 +63,8 @@ - Issue #11467: Fix urlparse behavior when handling urls which contains scheme specific part only digits. Patch by Santoso Wijaya. +- collections.Counter().copy() now works correctly for subclasses. + - Issue #11474: Fix the bug with url2pathname() handling of '/C|/' on Windows. Patch by Santoso Wijaya. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 15 22:23:22 2011 From: python-checkins at python.org (raymond.hettinger) Date: Fri, 15 Apr 2011 22:23:22 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Fix minor subclassing issue with collections.Counter Message-ID: http://hg.python.org/cpython/rev/4607c27bbab7 changeset: 69381:4607c27bbab7 parent: 69377:51ebdd888a43 parent: 69380:bb13260d56c6 user: Raymond Hettinger date: Fri Apr 15 13:23:01 2011 -0700 summary: Fix minor subclassing issue with collections.Counter files: Lib/collections/__init__.py | 4 ++-- Lib/test/test_collections.py | 9 +++++++++ Misc/NEWS | 2 ++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/Lib/collections/__init__.py b/Lib/collections/__init__.py --- a/Lib/collections/__init__.py +++ b/Lib/collections/__init__.py @@ -565,8 +565,8 @@ self.subtract(kwds) def copy(self): - 'Like dict.copy() but returns a Counter instance instead of a dict.' - return Counter(self) + 'Return a shallow copy.' + return self.__class__(self) def __reduce__(self): return self.__class__, (dict(self),) diff --git a/Lib/test/test_collections.py b/Lib/test/test_collections.py --- a/Lib/test/test_collections.py +++ b/Lib/test/test_collections.py @@ -870,6 +870,15 @@ self.assertEqual(len(dup), len(words)) self.assertEqual(type(dup), type(words)) + def test_copy_subclass(self): + class MyCounter(Counter): + pass + c = MyCounter('slartibartfast') + d = c.copy() + self.assertEqual(d, c) + self.assertEqual(len(d), len(c)) + self.assertEqual(type(d), type(c)) + def test_conversions(self): # Convert to: set, list, dict s = 'she sells sea shells by the sea shore' diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -113,6 +113,8 @@ - Issue #11467: Fix urlparse behavior when handling urls which contains scheme specific part only digits. Patch by Santoso Wijaya. +- collections.Counter().copy() now works correctly for subclasses. + - Issue #11474: Fix the bug with url2pathname() handling of '/C|/' on Windows. Patch by Santoso Wijaya. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 15 23:29:40 2011 From: python-checkins at python.org (vinay.sajip) Date: Fri, 15 Apr 2011 23:29:40 +0200 Subject: [Python-checkins] cpython (3.2): Issue #11852: Add missing imports and update tests. Message-ID: http://hg.python.org/cpython/rev/3b700e6704b3 changeset: 69382:3b700e6704b3 branch: 3.2 parent: 69380:bb13260d56c6 user: Vinay Sajip date: Fri Apr 15 22:27:17 2011 +0100 summary: Issue #11852: Add missing imports and update tests. files: Lib/logging/handlers.py | 2 ++ Lib/test/test_logging.py | 16 ++++++++++++++++ Misc/NEWS | 2 ++ 3 files changed, 20 insertions(+), 0 deletions(-) diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py --- a/Lib/logging/handlers.py +++ b/Lib/logging/handlers.py @@ -26,6 +26,8 @@ import logging, socket, os, pickle, struct, time, re from stat import ST_DEV, ST_INO, ST_MTIME +import queue +import threading try: import codecs 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 @@ -41,6 +41,7 @@ import sys import tempfile from test.support import captured_stdout, run_with_locale, run_unittest +from test.support import TestHandler, Matcher import textwrap import unittest import warnings @@ -2092,6 +2093,21 @@ self.assertEqual(data.name, self.que_logger.name) self.assertEqual((data.msg, data.args), (msg, None)) + def test_queue_listener(self): + handler = TestHandler(Matcher()) + listener = logging.handlers.QueueListener(self.queue, handler) + listener.start() + try: + self.que_logger.warning(self.next_message()) + self.que_logger.error(self.next_message()) + self.que_logger.critical(self.next_message()) + finally: + listener.stop() + self.assertTrue(handler.matches(levelno=logging.WARNING, message='1')) + self.assertTrue(handler.matches(levelno=logging.ERROR, message='2')) + self.assertTrue(handler.matches(levelno=logging.CRITICAL, message='3')) + + class FormatterTest(unittest.TestCase): def setUp(self): self.common = { diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -60,6 +60,8 @@ Library ------- +- Issue #11852: Add missing imports and update tests. + - Issue #11467: Fix urlparse behavior when handling urls which contains scheme specific part only digits. Patch by Santoso Wijaya. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 15 23:29:47 2011 From: python-checkins at python.org (vinay.sajip) Date: Fri, 15 Apr 2011 23:29:47 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Issue #11852: Merge fix from 3.2. Message-ID: http://hg.python.org/cpython/rev/f5a6367e11e2 changeset: 69383:f5a6367e11e2 parent: 69381:4607c27bbab7 parent: 69382:3b700e6704b3 user: Vinay Sajip date: Fri Apr 15 22:29:15 2011 +0100 summary: Issue #11852: Merge fix from 3.2. files: Lib/logging/handlers.py | 2 ++ Lib/test/test_logging.py | 16 ++++++++++++++++ Misc/NEWS | 2 ++ 3 files changed, 20 insertions(+), 0 deletions(-) diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py --- a/Lib/logging/handlers.py +++ b/Lib/logging/handlers.py @@ -26,6 +26,8 @@ import logging, socket, os, pickle, struct, time, re from stat import ST_DEV, ST_INO, ST_MTIME +import queue +import threading try: import codecs 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 @@ -41,6 +41,7 @@ import sys import tempfile from test.support import captured_stdout, run_with_locale, run_unittest, patch +from test.support import TestHandler, Matcher import textwrap import unittest import warnings @@ -2108,6 +2109,21 @@ self.assertEqual(data.name, self.que_logger.name) self.assertEqual((data.msg, data.args), (msg, None)) + def test_queue_listener(self): + handler = TestHandler(Matcher()) + listener = logging.handlers.QueueListener(self.queue, handler) + listener.start() + try: + self.que_logger.warning(self.next_message()) + self.que_logger.error(self.next_message()) + self.que_logger.critical(self.next_message()) + finally: + listener.stop() + self.assertTrue(handler.matches(levelno=logging.WARNING, message='1')) + self.assertTrue(handler.matches(levelno=logging.ERROR, message='2')) + self.assertTrue(handler.matches(levelno=logging.CRITICAL, message='3')) + + class FormatterTest(unittest.TestCase): def setUp(self): self.common = { diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -110,6 +110,8 @@ Library ------- +- Issue #11852: Add missing imports and update tests. + - Issue #11467: Fix urlparse behavior when handling urls which contains scheme specific part only digits. Patch by Santoso Wijaya. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 16 02:44:51 2011 From: python-checkins at python.org (raymond.hettinger) Date: Sat, 16 Apr 2011 02:44:51 +0200 Subject: [Python-checkins] cpython (3.1): Add another example to the collections module docs. Message-ID: http://hg.python.org/cpython/rev/9c8de0284c26 changeset: 69384:9c8de0284c26 branch: 3.1 parent: 69379:a164f67d27be user: Raymond Hettinger date: Fri Apr 15 17:43:19 2011 -0700 summary: Add another example to the collections module docs. files: Doc/library/collections.rst | 20 ++++++++++++++++++++ 1 files changed, 20 insertions(+), 0 deletions(-) diff --git a/Doc/library/collections.rst b/Doc/library/collections.rst --- a/Doc/library/collections.rst +++ b/Doc/library/collections.rst @@ -783,6 +783,9 @@ `Equivalent OrderedDict recipe `_ that runs on Python 2.4 or later. +:class:`OrderedDict` Examples and Recipes +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + Since an ordered dictionary remembers its insertion order, it can be used in conjuction with sorting to make a sorted dictionary:: @@ -812,11 +815,28 @@ class LastUpdatedOrderedDict(OrderedDict): 'Store items in the order the keys were last added' + def __setitem__(self, key, value): if key in self: del self[key] OrderedDict.__setitem__(self, key, value) +An ordered dictionary can combined with the :class:`Counter` class +so that the counter remembers the order elements are first encountered:: + + class OrderedCounter(Counter, OrderedDict): + 'Counter that remembers the order elements are first encountered' + + def __init__(self, iterable=None, **kwds): + OrderedDict.__init__(self) + Counter.__init__(self, iterable, **kwds) + + def __repr__(self): + return '%s(%r)' % (self.__class__.__name__, OrderedDict(self)) + + def __reduce__(self): + return self.__class__, (OrderedDict(self),) + :class:`UserDict` objects ------------------------- -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 16 02:44:53 2011 From: python-checkins at python.org (raymond.hettinger) Date: Sat, 16 Apr 2011 02:44:53 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): merge Message-ID: http://hg.python.org/cpython/rev/033dd346df57 changeset: 69385:033dd346df57 branch: 3.2 parent: 69382:3b700e6704b3 parent: 69384:9c8de0284c26 user: Raymond Hettinger date: Fri Apr 15 17:43:57 2011 -0700 summary: merge files: Doc/library/collections.rst | 20 ++++++++++++++++++++ 1 files changed, 20 insertions(+), 0 deletions(-) diff --git a/Doc/library/collections.rst b/Doc/library/collections.rst --- a/Doc/library/collections.rst +++ b/Doc/library/collections.rst @@ -845,6 +845,9 @@ `Equivalent OrderedDict recipe `_ that runs on Python 2.4 or later. +:class:`OrderedDict` Examples and Recipes +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + Since an ordered dictionary remembers its insertion order, it can be used in conjuction with sorting to make a sorted dictionary:: @@ -874,11 +877,28 @@ class LastUpdatedOrderedDict(OrderedDict): 'Store items in the order the keys were last added' + def __setitem__(self, key, value): if key in self: del self[key] OrderedDict.__setitem__(self, key, value) +An ordered dictionary can combined with the :class:`Counter` class +so that the counter remembers the order elements are first encountered:: + + class OrderedCounter(Counter, OrderedDict): + 'Counter that remembers the order elements are first encountered' + + def __init__(self, iterable=None, **kwds): + OrderedDict.__init__(self) + Counter.__init__(self, iterable, **kwds) + + def __repr__(self): + return '%s(%r)' % (self.__class__.__name__, OrderedDict(self)) + + def __reduce__(self): + return self.__class__, (OrderedDict(self),) + :class:`UserDict` objects ------------------------- -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 16 02:44:57 2011 From: python-checkins at python.org (raymond.hettinger) Date: Sat, 16 Apr 2011 02:44:57 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): merge Message-ID: http://hg.python.org/cpython/rev/49dabc676801 changeset: 69386:49dabc676801 parent: 69383:f5a6367e11e2 parent: 69385:033dd346df57 user: Raymond Hettinger date: Fri Apr 15 17:44:30 2011 -0700 summary: merge files: Doc/library/collections.rst | 20 ++++++++++++++++++++ 1 files changed, 20 insertions(+), 0 deletions(-) diff --git a/Doc/library/collections.rst b/Doc/library/collections.rst --- a/Doc/library/collections.rst +++ b/Doc/library/collections.rst @@ -927,6 +927,9 @@ `Equivalent OrderedDict recipe `_ that runs on Python 2.4 or later. +:class:`OrderedDict` Examples and Recipes +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + Since an ordered dictionary remembers its insertion order, it can be used in conjuction with sorting to make a sorted dictionary:: @@ -956,11 +959,28 @@ class LastUpdatedOrderedDict(OrderedDict): 'Store items in the order the keys were last added' + def __setitem__(self, key, value): if key in self: del self[key] OrderedDict.__setitem__(self, key, value) +An ordered dictionary can combined with the :class:`Counter` class +so that the counter remembers the order elements are first encountered:: + + class OrderedCounter(Counter, OrderedDict): + 'Counter that remembers the order elements are first encountered' + + def __init__(self, iterable=None, **kwds): + OrderedDict.__init__(self) + Counter.__init__(self, iterable, **kwds) + + def __repr__(self): + return '%s(%r)' % (self.__class__.__name__, OrderedDict(self)) + + def __reduce__(self): + return self.__class__, (OrderedDict(self),) + :class:`UserDict` objects ------------------------- -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 16 02:55:44 2011 From: python-checkins at python.org (raymond.hettinger) Date: Sat, 16 Apr 2011 02:55:44 +0200 Subject: [Python-checkins] cpython (2.7): Add another example to the collections module docs. Message-ID: http://hg.python.org/cpython/rev/6c5245427ccb changeset: 69387:6c5245427ccb branch: 2.7 parent: 69378:30d6bc10e862 user: Raymond Hettinger date: Fri Apr 15 17:55:36 2011 -0700 summary: Add another example to the collections module docs. files: Doc/library/collections.rst | 20 ++++++++++++++++++++ 1 files changed, 20 insertions(+), 0 deletions(-) diff --git a/Doc/library/collections.rst b/Doc/library/collections.rst --- a/Doc/library/collections.rst +++ b/Doc/library/collections.rst @@ -818,6 +818,9 @@ `Equivalent OrderedDict recipe `_ that runs on Python 2.4 or later. +:class:`OrderedDict` Examples and Recipes +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + Since an ordered dictionary remembers its insertion order, it can be used in conjuction with sorting to make a sorted dictionary:: @@ -846,12 +849,29 @@ original insertion position is changed and moved to the end:: class LastUpdatedOrderedDict(OrderedDict): + 'Store items in the order the keys were last added' def __setitem__(self, key, value): if key in self: del self[key] OrderedDict.__setitem__(self, key, value) +An ordered dictionary can combined with the :class:`Counter` class +so that the counter remembers the order elements are first encountered:: + + class OrderedCounter(Counter, OrderedDict): + 'Counter that remembers the order elements are first encountered' + + def __init__(self, iterable=None, **kwds): + OrderedDict.__init__(self) + Counter.__init__(self, iterable, **kwds) + + def __repr__(self): + return '%s(%r)' % (self.__class__.__name__, OrderedDict(self)) + + def __reduce__(self): + return self.__class__, (OrderedDict(self),) + .. _abstract-base-classes: -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Sat Apr 16 05:02:44 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sat, 16 Apr 2011 05:02:44 +0200 Subject: [Python-checkins] Daily reference leaks (49dabc676801): sum=-56 Message-ID: results for 49dabc676801 on branch "default" -------------------------------------------- test_pyexpat leaked [0, 0, -56] references, sum=-56 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogKKtNMh', '-x'] From python-checkins at python.org Sat Apr 16 14:10:54 2011 From: python-checkins at python.org (eli.bendersky) Date: Sat, 16 Apr 2011 14:10:54 +0200 Subject: [Python-checkins] cpython (2.7): Issue #11855: Apply missing formatting for urlretrieve Message-ID: http://hg.python.org/cpython/rev/d3e0bc155ca2 changeset: 69388:d3e0bc155ca2 branch: 2.7 user: Eli Bendersky date: Sat Apr 16 15:28:42 2011 +0300 summary: Issue #11855: Apply missing formatting for urlretrieve files: Doc/library/urllib.rst | 10 +++++----- 1 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Doc/library/urllib.rst b/Doc/library/urllib.rst --- a/Doc/library/urllib.rst +++ b/Doc/library/urllib.rst @@ -167,15 +167,15 @@ the download is interrupted. The *Content-Length* is treated as a lower bound: if there's more data to read, - urlretrieve reads more data, but if less data is available, it raises the - exception. + :func:`urlretrieve` reads more data, but if less data is available, it raises + the exception. You can still retrieve the downloaded data in this case, it is stored in the :attr:`content` attribute of the exception instance. - If no *Content-Length* header was supplied, urlretrieve can not check the size - of the data it has downloaded, and just returns it. In this case you just have - to assume that the download was successful. + If no *Content-Length* header was supplied, :func:`urlretrieve` can not check + the size of the data it has downloaded, and just returns it. In this case you + just have to assume that the download was successful. .. data:: _urlopener -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 16 14:18:20 2011 From: python-checkins at python.org (eli.bendersky) Date: Sat, 16 Apr 2011 14:18:20 +0200 Subject: [Python-checkins] cpython (3.1): Issue #11855: Apply missing formatting for urlretrieve Message-ID: http://hg.python.org/cpython/rev/a6d9f9329070 changeset: 69389:a6d9f9329070 branch: 3.1 parent: 69384:9c8de0284c26 user: Eli Bendersky date: Sat Apr 16 15:32:13 2011 +0300 summary: Issue #11855: Apply missing formatting for urlretrieve files: Doc/library/urllib.request.rst | 10 +++++----- 1 files changed, 5 insertions(+), 5 deletions(-) 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 @@ -120,15 +120,15 @@ the download is interrupted. The *Content-Length* is treated as a lower bound: if there's more data to read, - urlretrieve reads more data, but if less data is available, it raises the - exception. + :func:`urlretrieve` reads more data, but if less data is available, it raises + the exception. You can still retrieve the downloaded data in this case, it is stored in the :attr:`content` attribute of the exception instance. - If no *Content-Length* header was supplied, urlretrieve can not check the size - of the data it has downloaded, and just returns it. In this case you just have - to assume that the download was successful. + If no *Content-Length* header was supplied, :func:`urlretrieve` can not + check the size of the data it has downloaded, and just returns it. In + this case you just have to assume that the download was successful. .. function:: urlcleanup() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 16 14:18:21 2011 From: python-checkins at python.org (eli.bendersky) Date: Sat, 16 Apr 2011 14:18:21 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): Issue #11855: merge from 3.1 Message-ID: http://hg.python.org/cpython/rev/0f1199858714 changeset: 69390:0f1199858714 branch: 3.2 parent: 69385:033dd346df57 parent: 69389:a6d9f9329070 user: Eli Bendersky date: Sat Apr 16 15:34:29 2011 +0300 summary: Issue #11855: merge from 3.1 files: Doc/library/urllib.request.rst | 10 +++++----- 1 files changed, 5 insertions(+), 5 deletions(-) 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 @@ -1113,15 +1113,15 @@ the download is interrupted. The *Content-Length* is treated as a lower bound: if there's more data to read, - urlretrieve reads more data, but if less data is available, it raises the - exception. + :func:`urlretrieve` reads more data, but if less data is available, it raises + the exception. You can still retrieve the downloaded data in this case, it is stored in the :attr:`content` attribute of the exception instance. - If no *Content-Length* header was supplied, urlretrieve can not check the size - of the data it has downloaded, and just returns it. In this case you just have - to assume that the download was successful. + If no *Content-Length* header was supplied, :func:`urlretrieve` can not check + the size of the data it has downloaded, and just returns it. In this case + you just have to assume that the download was successful. .. function:: urlcleanup() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 16 14:18:25 2011 From: python-checkins at python.org (eli.bendersky) Date: Sat, 16 Apr 2011 14:18:25 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Issue #11855: merge from 3.2 Message-ID: http://hg.python.org/cpython/rev/c49c595e4214 changeset: 69391:c49c595e4214 parent: 69386:49dabc676801 parent: 69390:0f1199858714 user: Eli Bendersky date: Sat Apr 16 15:36:26 2011 +0300 summary: Issue #11855: merge from 3.2 files: Doc/library/urllib.request.rst | 10 +++++----- 1 files changed, 5 insertions(+), 5 deletions(-) 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 @@ -1113,15 +1113,15 @@ the download is interrupted. The *Content-Length* is treated as a lower bound: if there's more data to read, - urlretrieve reads more data, but if less data is available, it raises the - exception. + :func:`urlretrieve` reads more data, but if less data is available, it raises + the exception. You can still retrieve the downloaded data in this case, it is stored in the :attr:`content` attribute of the exception instance. - If no *Content-Length* header was supplied, urlretrieve can not check the size - of the data it has downloaded, and just returns it. In this case you just have - to assume that the download was successful. + If no *Content-Length* header was supplied, :func:`urlretrieve` can not check + the size of the data it has downloaded, and just returns it. In this case + you just have to assume that the download was successful. .. function:: urlcleanup() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 16 15:22:37 2011 From: python-checkins at python.org (r.david.murray) Date: Sat, 16 Apr 2011 15:22:37 +0200 Subject: [Python-checkins] cpython (3.2): Improve message.py test coverage to 100%. Message-ID: http://hg.python.org/cpython/rev/2596389a993d changeset: 69392:2596389a993d branch: 3.2 parent: 69390:0f1199858714 user: R David Murray date: Sat Apr 16 09:20:30 2011 -0400 summary: Improve message.py test coverage to 100%. coverage.py reports 99% on branch coverage, but that appears to be a bug or limitation in coverage.py. files: Lib/email/test/test_email.py | 56 ++++++++++++++++++++++++ 1 files changed, 56 insertions(+), 0 deletions(-) diff --git a/Lib/email/test/test_email.py b/Lib/email/test/test_email.py --- a/Lib/email/test/test_email.py +++ b/Lib/email/test/test_email.py @@ -236,6 +236,10 @@ msg.set_payload('foo') eq(msg.get_payload(decode=True), b'foo') + def test_get_payload_n_raises_on_non_multipart(self): + msg = Message() + self.assertRaises(TypeError, msg.get_payload, 1) + def test_decoded_generator(self): eq = self.assertEqual msg = self._msgobj('msg_07.txt') @@ -391,6 +395,17 @@ msg.del_param('filename', 'content-disposition') self.assertEqual(msg['content-disposition'], 'attachment') + def test_del_param_on_nonexistent_header(self): + msg = Message() + msg.del_param('filename', 'content-disposition') + + def test_del_nonexistent_param(self): + msg = Message() + msg.add_header('Content-Type', 'text/plain', charset='utf-8') + existing_header = msg['Content-Type'] + msg.del_param('foobar', header='Content-Type') + self.assertEqual(msg['Content-Type'], 'text/plain; charset="utf-8"') + def test_set_type(self): eq = self.assertEqual msg = Message() @@ -521,6 +536,27 @@ self.assertEqual(msg.get_payload(decode=True), bytes(x, 'raw-unicode-escape')) + def test_broken_unicode_payload(self): + # This test improves coverage but is not a compliance test. + # The behavior in this situation is currently undefined by the API. + x = 'this is a br\xf6ken thing to do' + msg = Message() + msg['content-type'] = 'text/plain' + msg['content-transfer-encoding'] = '8bit' + msg.set_payload(x) + self.assertEqual(msg.get_payload(decode=True), + bytes(x, 'raw-unicode-escape')) + + def test_questionable_bytes_payload(self): + # This test improves coverage but is not a compliance test, + # since it involves poking inside the black box. + x = 'this is a qu?stionable thing to do'.encode('utf-8') + msg = Message() + msg['content-type'] = 'text/plain; charset="utf-8"' + msg['content-transfer-encoding'] = '8bit' + msg._payload = x + self.assertEqual(msg.get_payload(decode=True), x) + # Issue 1078919 def test_ascii_add_header(self): msg = Message() @@ -561,6 +597,16 @@ "attachment; filename*=utf-8''Fu%C3%9Fballer%20%5Bfilename%5D.ppt", msg['Content-Disposition']) + def test_add_header_with_name_only_param(self): + msg = Message() + msg.add_header('Content-Disposition', 'inline', foo_bar=None) + self.assertEqual("inline; foo-bar", msg['Content-Disposition']) + + def test_add_header_with_no_value(self): + msg = Message() + msg.add_header('X-Status', None) + self.assertEqual('', msg['X-Status']) + # Issue 5871: reject an attempt to embed a header inside a header value # (header injection attack). def test_embeded_header_via_Header_rejected(self): @@ -4116,6 +4162,16 @@ -Me """) + def test_set_param_requote(self): + msg = Message() + msg.set_param('title', 'foo') + self.assertEqual(msg['content-type'], 'text/plain; title="foo"') + msg.set_param('title', 'bar', requote=False) + self.assertEqual(msg['content-type'], 'text/plain; title=bar') + # tspecial is still quoted. + msg.set_param('title', "(bar)bell", requote=False) + self.assertEqual(msg['content-type'], 'text/plain; title="(bar)bell"') + def test_del_param(self): eq = self.ndiffAssertEqual msg = self._msgobj('msg_01.txt') -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 16 15:22:38 2011 From: python-checkins at python.org (r.david.murray) Date: Sat, 16 Apr 2011 15:22:38 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge: Improve message.py test coverage to 100%. Message-ID: http://hg.python.org/cpython/rev/2aea51cb0d1d changeset: 69393:2aea51cb0d1d parent: 69391:c49c595e4214 parent: 69392:2596389a993d user: R David Murray date: Sat Apr 16 09:21:49 2011 -0400 summary: Merge: Improve message.py test coverage to 100%. coverage.py reports 99% on branch coverage, but that appears to be a bug or limitation in coverage.py. files: Lib/test/test_email/test_email.py | 56 +++++++++++++++++++ 1 files changed, 56 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_email/test_email.py b/Lib/test/test_email/test_email.py --- a/Lib/test/test_email/test_email.py +++ b/Lib/test/test_email/test_email.py @@ -221,6 +221,10 @@ msg.set_payload('foo') eq(msg.get_payload(decode=True), b'foo') + def test_get_payload_n_raises_on_non_multipart(self): + msg = Message() + self.assertRaises(TypeError, msg.get_payload, 1) + def test_decoded_generator(self): eq = self.assertEqual msg = self._msgobj('msg_07.txt') @@ -376,6 +380,17 @@ msg.del_param('filename', 'content-disposition') self.assertEqual(msg['content-disposition'], 'attachment') + def test_del_param_on_nonexistent_header(self): + msg = Message() + msg.del_param('filename', 'content-disposition') + + def test_del_nonexistent_param(self): + msg = Message() + msg.add_header('Content-Type', 'text/plain', charset='utf-8') + existing_header = msg['Content-Type'] + msg.del_param('foobar', header='Content-Type') + self.assertEqual(msg['Content-Type'], 'text/plain; charset="utf-8"') + def test_set_type(self): eq = self.assertEqual msg = Message() @@ -506,6 +521,27 @@ self.assertEqual(msg.get_payload(decode=True), bytes(x, 'raw-unicode-escape')) + def test_broken_unicode_payload(self): + # This test improves coverage but is not a compliance test. + # The behavior in this situation is currently undefined by the API. + x = 'this is a br\xf6ken thing to do' + msg = Message() + msg['content-type'] = 'text/plain' + msg['content-transfer-encoding'] = '8bit' + msg.set_payload(x) + self.assertEqual(msg.get_payload(decode=True), + bytes(x, 'raw-unicode-escape')) + + def test_questionable_bytes_payload(self): + # This test improves coverage but is not a compliance test, + # since it involves poking inside the black box. + x = 'this is a qu?stionable thing to do'.encode('utf-8') + msg = Message() + msg['content-type'] = 'text/plain; charset="utf-8"' + msg['content-transfer-encoding'] = '8bit' + msg._payload = x + self.assertEqual(msg.get_payload(decode=True), x) + # Issue 1078919 def test_ascii_add_header(self): msg = Message() @@ -546,6 +582,16 @@ "attachment; filename*=utf-8''Fu%C3%9Fballer%20%5Bfilename%5D.ppt", msg['Content-Disposition']) + def test_add_header_with_name_only_param(self): + msg = Message() + msg.add_header('Content-Disposition', 'inline', foo_bar=None) + self.assertEqual("inline; foo-bar", msg['Content-Disposition']) + + def test_add_header_with_no_value(self): + msg = Message() + msg.add_header('X-Status', None) + self.assertEqual('', msg['X-Status']) + # Issue 5871: reject an attempt to embed a header inside a header value # (header injection attack). def test_embeded_header_via_Header_rejected(self): @@ -4150,6 +4196,16 @@ -Me """) + def test_set_param_requote(self): + msg = Message() + msg.set_param('title', 'foo') + self.assertEqual(msg['content-type'], 'text/plain; title="foo"') + msg.set_param('title', 'bar', requote=False) + self.assertEqual(msg['content-type'], 'text/plain; title=bar') + # tspecial is still quoted. + msg.set_param('title', "(bar)bell", requote=False) + self.assertEqual(msg['content-type'], 'text/plain; title="(bar)bell"') + def test_del_param(self): eq = self.ndiffAssertEqual msg = self._msgobj('msg_01.txt') -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 16 16:51:05 2011 From: python-checkins at python.org (georg.brandl) Date: Sat, 16 Apr 2011 16:51:05 +0200 Subject: [Python-checkins] cpython: Consistency fix: "command line" is the noun, "command-line" the adjective. Message-ID: http://hg.python.org/cpython/rev/9fbbc8d79a09 changeset: 69394:9fbbc8d79a09 user: Georg Brandl date: Sat Apr 16 16:44:54 2011 +0200 summary: Consistency fix: "command line" is the noun, "command-line" the adjective. files: Doc/library/argparse.rst | 36 ++++++++++++++-------------- 1 files changed, 18 insertions(+), 18 deletions(-) diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -1,4 +1,4 @@ -:mod:`argparse` --- Parser for command line options, arguments and sub-commands +:mod:`argparse` --- Parser for command-line options, arguments and sub-commands =============================================================================== .. module:: argparse @@ -108,10 +108,10 @@ ^^^^^^^^^^^^^^^^^ :class:`ArgumentParser` parses args through the -:meth:`~ArgumentParser.parse_args` method. This will inspect the command-line, +:meth:`~ArgumentParser.parse_args` method. This will inspect the command line, convert each arg to the appropriate type and then invoke the appropriate action. In most cases, this means a simple namespace object will be built up from -attributes parsed out of the command-line:: +attributes parsed out of the command line:: >>> parser.parse_args(['--sum', '7', '-1', '42']) Namespace(accumulate=, integers=[7, -1, 42]) @@ -221,7 +221,7 @@ parser.add_argument('--foo', help='foo help') args = parser.parse_args() -If ``-h`` or ``--help`` is supplied is at the command-line, the ArgumentParser +If ``-h`` or ``--help`` is supplied is at the command line, the ArgumentParser help will be printed:: $ python myprogram.py --help @@ -594,21 +594,21 @@ [const], [default], [type], [choices], [required], \ [help], [metavar], [dest]) - Define how a single command line argument should be parsed. Each parameter + Define how a single command-line argument should be parsed. Each parameter has its own more detailed description below, but in short they are: * `name or flags`_ - Either a name or a list of option strings, e.g. ``foo`` or ``-f, --foo`` * action_ - The basic type of action to be taken when this argument is - encountered at the command-line. + encountered at the command line. * nargs_ - The number of command-line arguments that should be consumed. * const_ - A constant value required by some action_ and nargs_ selections. * default_ - The value produced if the argument is absent from the - command-line. + command line. * type_ - The type to which the command-line arg should be converted. @@ -768,7 +768,7 @@ different number of command-line arguments with a single action.. The supported values are: -* N (an integer). N args from the command-line will be gathered together into a +* N (an integer). N args from the command line will be gathered together into a list. For example:: >>> parser = argparse.ArgumentParser() @@ -780,7 +780,7 @@ Note that ``nargs=1`` produces a list of one item. This is different from the default, in which the item is produced by itself. -* ``'?'``. One arg will be consumed from the command-line if possible, and +* ``'?'``. One arg will be consumed from the command line if possible, and produced as a single item. If no command-line arg is present, the value from default_ will be produced. Note that for optional arguments, there is an additional case - the option string is present but not followed by a @@ -855,7 +855,7 @@ * When :meth:`add_argument` is called with option strings (like ``-f`` or ``--foo``) and ``nargs='?'``. This creates an optional argument that can be - followed by zero or one command-line args. When parsing the command-line, if + followed by zero or one command-line args. When parsing the command line, if the option string is encountered with no command-line arg following it, the value of ``const`` will be assumed instead. See the nargs_ description for examples. @@ -867,7 +867,7 @@ ^^^^^^^ All optional arguments and some positional arguments may be omitted at the -command-line. The ``default`` keyword argument of :meth:`add_argument`, whose +command line. The ``default`` keyword argument of :meth:`add_argument`, whose value defaults to ``None``, specifies what value should be used if the command-line arg is not present. For optional arguments, the ``default`` value is used when the option string was not present at the command line:: @@ -965,7 +965,7 @@ Some command-line args should be selected from a restricted set of values. These can be handled by passing a container object as the ``choices`` keyword -argument to :meth:`add_argument`. When the command-line is parsed, arg values +argument to :meth:`add_argument`. When the command line is parsed, arg values will be checked, and an error message will be displayed if the arg was not one of the acceptable values:: @@ -998,7 +998,7 @@ ^^^^^^^^ In general, the argparse module assumes that flags like ``-f`` and ``--bar`` -indicate *optional* arguments, which can always be omitted at the command-line. +indicate *optional* arguments, which can always be omitted at the command line. To make an option *required*, ``True`` can be specified for the ``required=`` keyword argument to :meth:`add_argument`:: @@ -1024,7 +1024,7 @@ The ``help`` value is a string containing a brief description of the argument. When a user requests help (usually by using ``-h`` or ``--help`` at the -command-line), these ``help`` descriptions will be displayed with each +command line), these ``help`` descriptions will be displayed with each argument:: >>> parser = argparse.ArgumentParser(prog='frobble') @@ -1195,7 +1195,7 @@ Namespace(foo='FOO', x=None) For long options (options with names longer than a single character), the option -and value can also be passed as a single command line argument, using ``=`` to +and value can also be passed as a single command-line argument, using ``=`` to separate them:: >>> parser.parse_args('--foo=FOO'.split()) @@ -1221,7 +1221,7 @@ Invalid arguments ^^^^^^^^^^^^^^^^^ -While parsing the command-line, ``parse_args`` checks for a variety of errors, +While parsing the command line, ``parse_args`` checks for a variety of errors, including ambiguous options, invalid types, invalid options, wrong number of positional arguments, etc. When it encounters such an error, it exits and prints the error along with a usage message:: @@ -1657,7 +1657,7 @@ Most of the time, the attributes of the object returned by :meth:`parse_args` will be fully determined by inspecting the command-line args and the argument actions. :meth:`ArgumentParser.set_defaults` allows some additional - attributes that are determined without any inspection of the command-line to + attributes that are determined without any inspection of the command line to be added:: >>> parser = argparse.ArgumentParser() @@ -1728,7 +1728,7 @@ .. method:: ArgumentParser.parse_known_args(args=None, namespace=None) -Sometimes a script may only parse a few of the command line arguments, passing +Sometimes a script may only parse a few of the command-line arguments, passing the remaining arguments on to another script or program. In these cases, the :meth:`parse_known_args` method can be useful. It works much like :meth:`~ArgumentParser.parse_args` except that it does not produce an error when -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 16 17:00:07 2011 From: python-checkins at python.org (georg.brandl) Date: Sat, 16 Apr 2011 17:00:07 +0200 Subject: [Python-checkins] cpython (3.1): Small wording fix. Message-ID: http://hg.python.org/cpython/rev/ff735436c247 changeset: 69395:ff735436c247 branch: 3.1 parent: 69389:a6d9f9329070 user: Georg Brandl date: Sat Apr 16 16:54:15 2011 +0200 summary: Small wording fix. files: Doc/library/json.rst | 7 ++++--- 1 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Doc/library/json.rst b/Doc/library/json.rst --- a/Doc/library/json.rst +++ b/Doc/library/json.rst @@ -158,9 +158,10 @@ .. note:: - Unlike :mod:`pickle` and :mod:`marshal`, JSON is not a framed protocol so - trying to serialize more objects with repeated calls to :func:`dump` and - the same *fp* will result in an invalid JSON file. + Unlike :mod:`pickle` and :mod:`marshal`, JSON is not a framed protocol, + so trying to serialize multiple objects with repeated calls to + :func:`dump` using the same *fp* will result in an invalid JSON file. + .. function:: load(fp, cls=None, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, object_pairs_hook=None, **kw) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 16 17:00:08 2011 From: python-checkins at python.org (georg.brandl) Date: Sat, 16 Apr 2011 17:00:08 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): Merge with 3.1 Message-ID: http://hg.python.org/cpython/rev/f1e3f77b8af8 changeset: 69396:f1e3f77b8af8 branch: 3.2 parent: 69392:2596389a993d parent: 69395:ff735436c247 user: Georg Brandl date: Sat Apr 16 16:59:32 2011 +0200 summary: Merge with 3.1 files: Doc/library/json.rst | 7 ++++--- 1 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Doc/library/json.rst b/Doc/library/json.rst --- a/Doc/library/json.rst +++ b/Doc/library/json.rst @@ -160,9 +160,10 @@ .. note:: - Unlike :mod:`pickle` and :mod:`marshal`, JSON is not a framed protocol so - trying to serialize more objects with repeated calls to :func:`dump` and - the same *fp* will result in an invalid JSON file. + Unlike :mod:`pickle` and :mod:`marshal`, JSON is not a framed protocol, + so trying to serialize multiple objects with repeated calls to + :func:`dump` using the same *fp* will result in an invalid JSON file. + .. function:: load(fp, cls=None, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, object_pairs_hook=None, **kw) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 16 17:00:09 2011 From: python-checkins at python.org (georg.brandl) Date: Sat, 16 Apr 2011 17:00:09 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge with 3.2 Message-ID: http://hg.python.org/cpython/rev/ef415ec1900b changeset: 69397:ef415ec1900b parent: 69394:9fbbc8d79a09 parent: 69396:f1e3f77b8af8 user: Georg Brandl date: Sat Apr 16 16:59:48 2011 +0200 summary: Merge with 3.2 files: Doc/library/json.rst | 7 ++++--- 1 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Doc/library/json.rst b/Doc/library/json.rst --- a/Doc/library/json.rst +++ b/Doc/library/json.rst @@ -160,9 +160,10 @@ .. note:: - Unlike :mod:`pickle` and :mod:`marshal`, JSON is not a framed protocol so - trying to serialize more objects with repeated calls to :func:`dump` and - the same *fp* will result in an invalid JSON file. + Unlike :mod:`pickle` and :mod:`marshal`, JSON is not a framed protocol, + so trying to serialize multiple objects with repeated calls to + :func:`dump` using the same *fp* will result in an invalid JSON file. + .. function:: load(fp, cls=None, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, object_pairs_hook=None, **kw) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 16 17:03:05 2011 From: python-checkins at python.org (georg.brandl) Date: Sat, 16 Apr 2011 17:03:05 +0200 Subject: [Python-checkins] cpython: Fix duplicate "is". Message-ID: http://hg.python.org/cpython/rev/8a9f8f34d9d5 changeset: 69398:8a9f8f34d9d5 user: Georg Brandl date: Sat Apr 16 17:02:58 2011 +0200 summary: Fix duplicate "is". files: Doc/library/argparse.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -221,7 +221,7 @@ parser.add_argument('--foo', help='foo help') args = parser.parse_args() -If ``-h`` or ``--help`` is supplied is at the command line, the ArgumentParser +If ``-h`` or ``--help`` is supplied at the command line, the ArgumentParser help will be printed:: $ python myprogram.py --help -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 16 17:07:17 2011 From: python-checkins at python.org (georg.brandl) Date: Sat, 16 Apr 2011 17:07:17 +0200 Subject: [Python-checkins] cpython (3.2): Backport 8a9f8f34d9d5. Message-ID: http://hg.python.org/cpython/rev/78825b299282 changeset: 69399:78825b299282 branch: 3.2 parent: 69396:f1e3f77b8af8 user: Georg Brandl date: Sat Apr 16 17:05:30 2011 +0200 summary: Backport 8a9f8f34d9d5. files: Doc/library/argparse.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -221,7 +221,7 @@ parser.add_argument('--foo', help='foo help') args = parser.parse_args() -If ``-h`` or ``--help`` is supplied is at the command-line, the ArgumentParser +If ``-h`` or ``--help`` is supplied at the command-line, the ArgumentParser help will be printed:: $ python myprogram.py --help -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 16 17:07:18 2011 From: python-checkins at python.org (georg.brandl) Date: Sat, 16 Apr 2011 17:07:18 +0200 Subject: [Python-checkins] cpython (3.2): Consistency fix: "command line" is the noun, "command-line" the adjective. Message-ID: http://hg.python.org/cpython/rev/59483e207650 changeset: 69400:59483e207650 branch: 3.2 user: Georg Brandl date: Sat Apr 16 16:44:54 2011 +0200 summary: Consistency fix: "command line" is the noun, "command-line" the adjective. files: Doc/library/argparse.rst | 36 ++++++++++++++-------------- 1 files changed, 18 insertions(+), 18 deletions(-) diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -1,4 +1,4 @@ -:mod:`argparse` --- Parser for command line options, arguments and sub-commands +:mod:`argparse` --- Parser for command-line options, arguments and sub-commands =============================================================================== .. module:: argparse @@ -108,10 +108,10 @@ ^^^^^^^^^^^^^^^^^ :class:`ArgumentParser` parses args through the -:meth:`~ArgumentParser.parse_args` method. This will inspect the command-line, +:meth:`~ArgumentParser.parse_args` method. This will inspect the command line, convert each arg to the appropriate type and then invoke the appropriate action. In most cases, this means a simple namespace object will be built up from -attributes parsed out of the command-line:: +attributes parsed out of the command line:: >>> parser.parse_args(['--sum', '7', '-1', '42']) Namespace(accumulate=, integers=[7, -1, 42]) @@ -221,7 +221,7 @@ parser.add_argument('--foo', help='foo help') args = parser.parse_args() -If ``-h`` or ``--help`` is supplied at the command-line, the ArgumentParser +If ``-h`` or ``--help`` is supplied at the command line, the ArgumentParser help will be printed:: $ python myprogram.py --help @@ -578,21 +578,21 @@ [const], [default], [type], [choices], [required], \ [help], [metavar], [dest]) - Define how a single command line argument should be parsed. Each parameter + Define how a single command-line argument should be parsed. Each parameter has its own more detailed description below, but in short they are: * `name or flags`_ - Either a name or a list of option strings, e.g. ``foo`` or ``-f, --foo`` * action_ - The basic type of action to be taken when this argument is - encountered at the command-line. + encountered at the command line. * nargs_ - The number of command-line arguments that should be consumed. * const_ - A constant value required by some action_ and nargs_ selections. * default_ - The value produced if the argument is absent from the - command-line. + command line. * type_ - The type to which the command-line arg should be converted. @@ -752,7 +752,7 @@ different number of command-line arguments with a single action.. The supported values are: -* N (an integer). N args from the command-line will be gathered together into a +* N (an integer). N args from the command line will be gathered together into a list. For example:: >>> parser = argparse.ArgumentParser() @@ -764,7 +764,7 @@ Note that ``nargs=1`` produces a list of one item. This is different from the default, in which the item is produced by itself. -* ``'?'``. One arg will be consumed from the command-line if possible, and +* ``'?'``. One arg will be consumed from the command line if possible, and produced as a single item. If no command-line arg is present, the value from default_ will be produced. Note that for optional arguments, there is an additional case - the option string is present but not followed by a @@ -839,7 +839,7 @@ * When :meth:`add_argument` is called with option strings (like ``-f`` or ``--foo``) and ``nargs='?'``. This creates an optional argument that can be - followed by zero or one command-line args. When parsing the command-line, if + followed by zero or one command-line args. When parsing the command line, if the option string is encountered with no command-line arg following it, the value of ``const`` will be assumed instead. See the nargs_ description for examples. @@ -851,7 +851,7 @@ ^^^^^^^ All optional arguments and some positional arguments may be omitted at the -command-line. The ``default`` keyword argument of :meth:`add_argument`, whose +command line. The ``default`` keyword argument of :meth:`add_argument`, whose value defaults to ``None``, specifies what value should be used if the command-line arg is not present. For optional arguments, the ``default`` value is used when the option string was not present at the command line:: @@ -949,7 +949,7 @@ Some command-line args should be selected from a restricted set of values. These can be handled by passing a container object as the ``choices`` keyword -argument to :meth:`add_argument`. When the command-line is parsed, arg values +argument to :meth:`add_argument`. When the command line is parsed, arg values will be checked, and an error message will be displayed if the arg was not one of the acceptable values:: @@ -982,7 +982,7 @@ ^^^^^^^^ In general, the argparse module assumes that flags like ``-f`` and ``--bar`` -indicate *optional* arguments, which can always be omitted at the command-line. +indicate *optional* arguments, which can always be omitted at the command line. To make an option *required*, ``True`` can be specified for the ``required=`` keyword argument to :meth:`add_argument`:: @@ -1008,7 +1008,7 @@ The ``help`` value is a string containing a brief description of the argument. When a user requests help (usually by using ``-h`` or ``--help`` at the -command-line), these ``help`` descriptions will be displayed with each +command line), these ``help`` descriptions will be displayed with each argument:: >>> parser = argparse.ArgumentParser(prog='frobble') @@ -1179,7 +1179,7 @@ Namespace(foo='FOO', x=None) For long options (options with names longer than a single character), the option -and value can also be passed as a single command line argument, using ``=`` to +and value can also be passed as a single command-line argument, using ``=`` to separate them:: >>> parser.parse_args('--foo=FOO'.split()) @@ -1205,7 +1205,7 @@ Invalid arguments ^^^^^^^^^^^^^^^^^ -While parsing the command-line, ``parse_args`` checks for a variety of errors, +While parsing the command line, ``parse_args`` checks for a variety of errors, including ambiguous options, invalid types, invalid options, wrong number of positional arguments, etc. When it encounters such an error, it exits and prints the error along with a usage message:: @@ -1641,7 +1641,7 @@ Most of the time, the attributes of the object returned by :meth:`parse_args` will be fully determined by inspecting the command-line args and the argument actions. :meth:`ArgumentParser.set_defaults` allows some additional - attributes that are determined without any inspection of the command-line to + attributes that are determined without any inspection of the command line to be added:: >>> parser = argparse.ArgumentParser() @@ -1712,7 +1712,7 @@ .. method:: ArgumentParser.parse_known_args(args=None, namespace=None) -Sometimes a script may only parse a few of the command line arguments, passing +Sometimes a script may only parse a few of the command-line arguments, passing the remaining arguments on to another script or program. In these cases, the :meth:`parse_known_args` method can be useful. It works much like :meth:`~ArgumentParser.parse_args` except that it does not produce an error when -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 16 17:07:20 2011 From: python-checkins at python.org (georg.brandl) Date: Sat, 16 Apr 2011 17:07:20 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge with 3.2. Message-ID: http://hg.python.org/cpython/rev/8c004b477087 changeset: 69401:8c004b477087 parent: 69398:8a9f8f34d9d5 parent: 69400:59483e207650 user: Georg Brandl date: Sat Apr 16 17:07:06 2011 +0200 summary: Merge with 3.2. files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 16 18:55:21 2011 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 16 Apr 2011 18:55:21 +0200 Subject: [Python-checkins] cpython (3.2): Fix possible "file already exists" error when running the tests in parallel. Message-ID: http://hg.python.org/cpython/rev/11c489dc8cbd changeset: 69402:11c489dc8cbd branch: 3.2 parent: 69400:59483e207650 user: Antoine Pitrou date: Sat Apr 16 18:53:59 2011 +0200 summary: Fix possible "file already exists" error when running the tests in parallel. This is a perfect example of LBYL going wrong: that code could be executed by several workers in parallel, and os.mkdir() attempted on the same path by multiple processes. files: Lib/test/regrtest.py | 6 +++++- Misc/NEWS | 2 ++ 2 files changed, 7 insertions(+), 1 deletions(-) diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -162,6 +162,7 @@ import io import sys import time +import errno import traceback import warnings import unittest @@ -1511,8 +1512,11 @@ if sysconfig.is_python_build(): TEMPDIR = os.path.join(sysconfig.get_config_var('srcdir'), 'build') TEMPDIR = os.path.abspath(TEMPDIR) - if not os.path.exists(TEMPDIR): + try: os.mkdir(TEMPDIR) + except OSError as e: + if e.errno != errno.EEXIST: + raise # Define a writable temp dir that will be used as cwd while running # the tests. The name of the dir includes the pid to allow parallel diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -269,6 +269,8 @@ Tests ----- +- Fix possible "file already exists" error when running the tests in parallel. + - Issue #11719: Fix message about unexpected test_msilib skip on non-Windows platforms. Patch by Nadeem Vawda. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 16 18:55:22 2011 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 16 Apr 2011 18:55:22 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge from 3.2 Message-ID: http://hg.python.org/cpython/rev/7323bced3d48 changeset: 69403:7323bced3d48 parent: 69401:8c004b477087 parent: 69402:11c489dc8cbd user: Antoine Pitrou date: Sat Apr 16 18:55:16 2011 +0200 summary: Merge from 3.2 files: Lib/test/regrtest.py | 6 +++++- Misc/NEWS | 2 ++ 2 files changed, 7 insertions(+), 1 deletions(-) diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -170,6 +170,7 @@ import io import sys import time +import errno import traceback import warnings import unittest @@ -1569,8 +1570,11 @@ if sysconfig.is_python_build(): TEMPDIR = os.path.join(sysconfig.get_config_var('srcdir'), 'build') TEMPDIR = os.path.abspath(TEMPDIR) - if not os.path.exists(TEMPDIR): + try: os.mkdir(TEMPDIR) + except OSError as e: + if e.errno != errno.EEXIST: + raise # Define a writable temp dir that will be used as cwd while running # the tests. The name of the dir includes the pid to allow parallel diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -475,6 +475,8 @@ Tests ----- +- Fix possible "file already exists" error when running the tests in parallel. + - Issue #11719: Fix message about unexpected test_msilib skip on non-Windows platforms. Patch by Nadeem Vawda. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 16 21:03:06 2011 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 16 Apr 2011 21:03:06 +0200 Subject: [Python-checkins] cpython (3.2): Issue #11790: Fix sporadic failures in Message-ID: http://hg.python.org/cpython/rev/88f1907fe312 changeset: 69404:88f1907fe312 branch: 3.2 parent: 69402:11c489dc8cbd user: Antoine Pitrou date: Sat Apr 16 21:02:01 2011 +0200 summary: Issue #11790: Fix sporadic failures in test_multiprocessing.WithProcessesTestCondition. files: Lib/test/test_multiprocessing.py | 8 +++++++- Misc/NEWS | 2 ++ 2 files changed, 9 insertions(+), 1 deletions(-) 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 @@ -757,7 +757,13 @@ cond.release() # check they have all woken - time.sleep(DELTA) + for i in range(10): + try: + if get_value(woken) == 6: + break + except NotImplementedError: + break + time.sleep(DELTA) self.assertReturnsIfImplemented(6, get_value, woken) # check state is not mucked up diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -269,6 +269,8 @@ Tests ----- +- Issue #11790: Fix sporadic failures in test_multiprocessing.WithProcessesTestCondition. + - Fix possible "file already exists" error when running the tests in parallel. - Issue #11719: Fix message about unexpected test_msilib skip on non-Windows -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 16 21:03:07 2011 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 16 Apr 2011 21:03:07 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Issue #11790: Fix sporadic failures in Message-ID: http://hg.python.org/cpython/rev/0ecfa2ce6561 changeset: 69405:0ecfa2ce6561 parent: 69403:7323bced3d48 parent: 69404:88f1907fe312 user: Antoine Pitrou date: Sat Apr 16 21:02:38 2011 +0200 summary: Issue #11790: Fix sporadic failures in test_multiprocessing.WithProcessesTestCondition. files: Lib/test/test_multiprocessing.py | 8 +++++++- Misc/NEWS | 2 ++ 2 files changed, 9 insertions(+), 1 deletions(-) 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 @@ -769,7 +769,13 @@ cond.release() # check they have all woken - time.sleep(DELTA) + for i in range(10): + try: + if get_value(woken) == 6: + break + except NotImplementedError: + break + time.sleep(DELTA) self.assertReturnsIfImplemented(6, get_value, woken) # check state is not mucked up diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -475,6 +475,8 @@ Tests ----- +- Issue #11790: Fix sporadic failures in test_multiprocessing.WithProcessesTestCondition. + - Fix possible "file already exists" error when running the tests in parallel. - Issue #11719: Fix message about unexpected test_msilib skip on non-Windows -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 16 22:14:58 2011 From: python-checkins at python.org (ezio.melotti) Date: Sat, 16 Apr 2011 22:14:58 +0200 Subject: [Python-checkins] cpython (2.7): Fix a few hyphens in argparse.rst. Message-ID: http://hg.python.org/cpython/rev/cc65cf9a9ce5 changeset: 69406:cc65cf9a9ce5 branch: 2.7 parent: 69388:d3e0bc155ca2 user: Ezio Melotti date: Sat Apr 16 23:04:51 2011 +0300 summary: Fix a few hyphens in argparse.rst. files: Doc/library/argparse.rst | 42 ++++++++++++++-------------- 1 files changed, 21 insertions(+), 21 deletions(-) diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -1,14 +1,14 @@ -:mod:`argparse` --- Parser for command line options, arguments and sub-commands +:mod:`argparse` --- Parser for command-line options, arguments and sub-commands =============================================================================== .. module:: argparse - :synopsis: Command-line option and argument parsing library. + :synopsis: Command-line option and argument-parsing library. .. moduleauthor:: Steven Bethard .. versionadded:: 2.7 .. sectionauthor:: Steven Bethard -The :mod:`argparse` module makes it easy to write user friendly command line +The :mod:`argparse` module makes it easy to write user-friendly command-line interfaces. The program defines what arguments it requires, and :mod:`argparse` will figure out how to parse those out of :data:`sys.argv`. The :mod:`argparse` module also automatically generates help and usage messages and issues errors @@ -104,10 +104,10 @@ ^^^^^^^^^^^^^^^^^ :class:`ArgumentParser` parses args through the -:meth:`~ArgumentParser.parse_args` method. This will inspect the command-line, +:meth:`~ArgumentParser.parse_args` method. This will inspect the command line, convert each arg to the appropriate type and then invoke the appropriate action. In most cases, this means a simple namespace object will be built up from -attributes parsed out of the command-line:: +attributes parsed out of the command line:: >>> parser.parse_args(['--sum', '7', '-1', '42']) Namespace(accumulate=, integers=[7, -1, 42]) @@ -217,7 +217,7 @@ parser.add_argument('--foo', help='foo help') args = parser.parse_args() -If ``-h`` or ``--help`` is supplied is at the command-line, the ArgumentParser +If ``-h`` or ``--help`` is supplied at the command line, the ArgumentParser help will be printed:: $ python myprogram.py --help @@ -574,23 +574,23 @@ [const], [default], [type], [choices], [required], \ [help], [metavar], [dest]) - Define how a single command line argument should be parsed. Each parameter + Define how a single command-line argument should be parsed. Each parameter has its own more detailed description below, but in short they are: * `name or flags`_ - Either a name or a list of option strings, e.g. ``foo`` or ``-f, --foo`` * action_ - The basic type of action to be taken when this argument is - encountered at the command-line. + encountered at the command line. * nargs_ - The number of command-line arguments that should be consumed. * const_ - A constant value required by some action_ and nargs_ selections. * default_ - The value produced if the argument is absent from the - command-line. + command line. - * type_ - The type to which the command-line arg should be converted. + * type_ - The type to which the command-line argument should be converted. * choices_ - A container of the allowable values for the argument. @@ -748,7 +748,7 @@ different number of command-line arguments with a single action.. The supported values are: -* N (an integer). N args from the command-line will be gathered together into a +* N (an integer). N args from the command line will be gathered together into a list. For example:: >>> parser = argparse.ArgumentParser() @@ -760,7 +760,7 @@ Note that ``nargs=1`` produces a list of one item. This is different from the default, in which the item is produced by itself. -* ``'?'``. One arg will be consumed from the command-line if possible, and +* ``'?'``. One arg will be consumed from the command line if possible, and produced as a single item. If no command-line arg is present, the value from default_ will be produced. Note that for optional arguments, there is an additional case - the option string is present but not followed by a @@ -835,7 +835,7 @@ * When :meth:`add_argument` is called with option strings (like ``-f`` or ``--foo``) and ``nargs='?'``. This creates an optional argument that can be - followed by zero or one command-line args. When parsing the command-line, if + followed by zero or one command-line args. When parsing the command line, if the option string is encountered with no command-line arg following it, the value of ``const`` will be assumed instead. See the nargs_ description for examples. @@ -847,7 +847,7 @@ ^^^^^^^ All optional arguments and some positional arguments may be omitted at the -command-line. The ``default`` keyword argument of :meth:`add_argument`, whose +command line. The ``default`` keyword argument of :meth:`add_argument`, whose value defaults to ``None``, specifies what value should be used if the command-line arg is not present. For optional arguments, the ``default`` value is used when the option string was not present at the command line:: @@ -945,7 +945,7 @@ Some command-line args should be selected from a restricted set of values. These can be handled by passing a container object as the ``choices`` keyword -argument to :meth:`add_argument`. When the command-line is parsed, arg values +argument to :meth:`add_argument`. When the command line is parsed, arg values will be checked, and an error message will be displayed if the arg was not one of the acceptable values:: @@ -978,7 +978,7 @@ ^^^^^^^^ In general, the argparse module assumes that flags like ``-f`` and ``--bar`` -indicate *optional* arguments, which can always be omitted at the command-line. +indicate *optional* arguments, which can always be omitted at the command line. To make an option *required*, ``True`` can be specified for the ``required=`` keyword argument to :meth:`add_argument`:: @@ -1004,7 +1004,7 @@ The ``help`` value is a string containing a brief description of the argument. When a user requests help (usually by using ``-h`` or ``--help`` at the -command-line), these ``help`` descriptions will be displayed with each +command line), these ``help`` descriptions will be displayed with each argument:: >>> parser = argparse.ArgumentParser(prog='frobble') @@ -1175,7 +1175,7 @@ Namespace(foo='FOO', x=None) For long options (options with names longer than a single character), the option -and value can also be passed as a single command line argument, using ``=`` to +and value can also be passed as a single command-line argument, using ``=`` to separate them:: >>> parser.parse_args('--foo=FOO'.split()) @@ -1201,7 +1201,7 @@ Invalid arguments ^^^^^^^^^^^^^^^^^ -While parsing the command-line, ``parse_args`` checks for a variety of errors, +While parsing the command line, ``parse_args`` checks for a variety of errors, including ambiguous options, invalid types, invalid options, wrong number of positional arguments, etc. When it encounters such an error, it exits and prints the error along with a usage message:: @@ -1627,7 +1627,7 @@ Most of the time, the attributes of the object returned by :meth:`parse_args` will be fully determined by inspecting the command-line args and the argument actions. :meth:`ArgumentParser.set_defaults` allows some additional - attributes that are determined without any inspection of the command-line to + attributes that are determined without any inspection of the command line to be added:: >>> parser = argparse.ArgumentParser() @@ -1698,7 +1698,7 @@ .. method:: ArgumentParser.parse_known_args(args=None, namespace=None) -Sometimes a script may only parse a few of the command line arguments, passing +Sometimes a script may only parse a few of the command-line arguments, passing the remaining arguments on to another script or program. In these cases, the :meth:`parse_known_args` method can be useful. It works much like :meth:`~ArgumentParser.parse_args` except that it does not produce an error when -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 16 22:14:59 2011 From: python-checkins at python.org (ezio.melotti) Date: Sat, 16 Apr 2011 22:14:59 +0200 Subject: [Python-checkins] cpython (3.2): Fix a few more hyphens in argparse.rst Message-ID: http://hg.python.org/cpython/rev/fcce2f49ef6d changeset: 69407:fcce2f49ef6d branch: 3.2 parent: 69404:88f1907fe312 user: Ezio Melotti date: Sat Apr 16 23:13:50 2011 +0300 summary: Fix a few more hyphens in argparse.rst files: Doc/library/argparse.rst | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -2,7 +2,7 @@ =============================================================================== .. module:: argparse - :synopsis: Command-line option and argument parsing library. + :synopsis: Command-line option and argument-parsing library. .. moduleauthor:: Steven Bethard .. sectionauthor:: Steven Bethard @@ -12,7 +12,7 @@ -------------- -The :mod:`argparse` module makes it easy to write user friendly command line +The :mod:`argparse` module makes it easy to write user-friendly command-line interfaces. The program defines what arguments it requires, and :mod:`argparse` will figure out how to parse those out of :data:`sys.argv`. The :mod:`argparse` module also automatically generates help and usage messages and issues errors @@ -594,7 +594,7 @@ * default_ - The value produced if the argument is absent from the command line. - * type_ - The type to which the command-line arg should be converted. + * type_ - The type to which the command-line argument should be converted. * choices_ - A container of the allowable values for the argument. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 16 22:14:59 2011 From: python-checkins at python.org (ezio.melotti) Date: Sat, 16 Apr 2011 22:14:59 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge with 3.2. Message-ID: http://hg.python.org/cpython/rev/c33596e6f723 changeset: 69408:c33596e6f723 parent: 69405:0ecfa2ce6561 parent: 69407:fcce2f49ef6d user: Ezio Melotti date: Sat Apr 16 23:14:40 2011 +0300 summary: Merge with 3.2. files: Doc/library/argparse.rst | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -2,7 +2,7 @@ =============================================================================== .. module:: argparse - :synopsis: Command-line option and argument parsing library. + :synopsis: Command-line option and argument-parsing library. .. moduleauthor:: Steven Bethard .. sectionauthor:: Steven Bethard @@ -12,7 +12,7 @@ -------------- -The :mod:`argparse` module makes it easy to write user friendly command line +The :mod:`argparse` module makes it easy to write user-friendly command-line interfaces. The program defines what arguments it requires, and :mod:`argparse` will figure out how to parse those out of :data:`sys.argv`. The :mod:`argparse` module also automatically generates help and usage messages and issues errors @@ -610,7 +610,7 @@ * default_ - The value produced if the argument is absent from the command line. - * type_ - The type to which the command-line arg should be converted. + * type_ - The type to which the command-line argument should be converted. * choices_ - A container of the allowable values for the argument. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 16 22:47:36 2011 From: python-checkins at python.org (brett.cannon) Date: Sat, 16 Apr 2011 22:47:36 +0200 Subject: [Python-checkins] peps: Minor clarification Message-ID: http://hg.python.org/peps/rev/6841c20e6857 changeset: 3869:6841c20e6857 user: Brett Cannon date: Sat Apr 16 13:47:30 2011 -0700 summary: Minor clarification files: pep-0399.txt | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pep-0399.txt b/pep-0399.txt --- a/pep-0399.txt +++ b/pep-0399.txt @@ -35,9 +35,9 @@ A problem all of the VMs other than CPython face is handling modules from the standard library that are implemented (to some extent) in C. -Since they do not typically support the entire `C API of Python`_ they -are unable to use the code used to create the module. Often times this -leads these other VMs to either re-implement the modules in pure +Since they do not typically support the entire `C API of CPython`_ +they are unable to use the code used to create the module. Often times +this leads these other VMs to either re-implement the modules in pure Python or in the programming language used to implement the VM (e.g., in C# for IronPython). This duplication of effort between CPython, PyPy, Jython, and IronPython is extremely unfortunate as @@ -231,5 +231,5 @@ .. _IronPython: http://ironpython.net/ .. _Jython: http://www.jython.org/ .. _PyPy: http://pypy.org/ -.. _C API of Python: http://docs.python.org/py3k/c-api/index.html +.. _C API of CPython: http://docs.python.org/py3k/c-api/index.html .. _sqlite3: http://docs.python.org/py3k/library/sqlite3.html -- Repository URL: http://hg.python.org/peps From solipsis at pitrou.net Sun Apr 17 04:59:25 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sun, 17 Apr 2011 04:59:25 +0200 Subject: [Python-checkins] Daily reference leaks (c33596e6f723): sum=0 Message-ID: results for c33596e6f723 on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogZOEhRl', '-x'] From python-checkins at python.org Sun Apr 17 22:31:34 2011 From: python-checkins at python.org (martin.v.loewis) Date: Sun, 17 Apr 2011 22:31:34 +0200 (CEST) Subject: [Python-checkins] r88815 - python/branches/release25-maint/Lib/SimpleHTTPServer.py Message-ID: <3QCPQZ60cFz7Lk4@mail.python.org> Author: martin.v.loewis Date: Sun Apr 17 22:31:34 2011 New Revision: 88815 Log: Copy of e9724d7abbc2 by Senthil Kumaran: Fix issue11442 - Add a charset parameter to the Content-type to avoid XSS attacks. Patch by Tom N. (Backported from py3k codeline). Modified: python/branches/release25-maint/Lib/SimpleHTTPServer.py Modified: python/branches/release25-maint/Lib/SimpleHTTPServer.py ============================================================================== --- python/branches/release25-maint/Lib/SimpleHTTPServer.py (original) +++ python/branches/release25-maint/Lib/SimpleHTTPServer.py Sun Apr 17 22:31:34 2011 @@ -16,6 +16,7 @@ import urllib import urlparse import cgi +import sys import shutil import mimetypes try: @@ -132,7 +133,8 @@ length = f.tell() f.seek(0) self.send_response(200) - self.send_header("Content-type", "text/html") + encoding = sys.getfilesystemencoding() + self.send_header("Content-type", "text/html; charset=%s" % encoding) self.send_header("Content-Length", str(length)) self.end_headers() return f From python-checkins at python.org Sun Apr 17 22:33:14 2011 From: python-checkins at python.org (martin.v.loewis) Date: Sun, 17 Apr 2011 22:33:14 +0200 (CEST) Subject: [Python-checkins] r88816 - python/branches/release25-maint/README Message-ID: <3QCPSV2mpxz7Ljk@mail.python.org> Author: martin.v.loewis Date: Sun Apr 17 22:33:14 2011 New Revision: 88816 Log: hg 3074c77b7121 by Guido van Rossum: Test commit. Add 2011 to copyright line. Modified: python/branches/release25-maint/README Modified: python/branches/release25-maint/README ============================================================================== --- python/branches/release25-maint/README (original) +++ python/branches/release25-maint/README Sun Apr 17 22:33:14 2011 @@ -1,9 +1,7 @@ This is Python version 2.5.5 ============================ -Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Python Software -Foundation. -All rights reserved. +Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Python Software Foundation. All rights reserved. Copyright (c) 2000 BeOpen.com. All rights reserved. From python-checkins at python.org Sun Apr 17 22:34:54 2011 From: python-checkins at python.org (martin.v.loewis) Date: Sun, 17 Apr 2011 22:34:54 +0200 (CEST) Subject: [Python-checkins] r88817 - python/branches/release25-maint/README Message-ID: <3QCPVQ0YQNz7Ljk@mail.python.org> Author: martin.v.loewis Date: Sun Apr 17 22:34:53 2011 New Revision: 88817 Log: hg cc959f114739 by Guido van Rossum: Whoops. The copyright should be two lines. Modified: python/branches/release25-maint/README Modified: python/branches/release25-maint/README ============================================================================== --- python/branches/release25-maint/README (original) +++ python/branches/release25-maint/README Sun Apr 17 22:34:53 2011 @@ -1,7 +1,8 @@ This is Python version 2.5.5 ============================ -Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Python Software Foundation. All rights reserved. +Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 +Python Software Foundation. All rights reserved. Copyright (c) 2000 BeOpen.com. All rights reserved. From python-checkins at python.org Sun Apr 17 22:36:17 2011 From: python-checkins at python.org (martin.v.loewis) Date: Sun, 17 Apr 2011 22:36:17 +0200 (CEST) Subject: [Python-checkins] r88818 - python/branches/release25-maint/Python/sysmodule.c Message-ID: <3QCPX14Hr7z7Ljk@mail.python.org> Author: martin.v.loewis Date: Sun Apr 17 22:36:17 2011 New Revision: 88818 Log: hg f9763c363cc3 by Martin v. L?wis Set subversion version identification to empty strings if this is not a subversion checkout (but a mercurial one). Closes #11579. Closes #11421. Patch by Senthil Kumaran. Modified: python/branches/release25-maint/Python/sysmodule.c Modified: python/branches/release25-maint/Python/sysmodule.c ============================================================================== --- python/branches/release25-maint/Python/sysmodule.c (original) +++ python/branches/release25-maint/Python/sysmodule.c Sun Apr 17 22:36:17 2011 @@ -978,8 +978,13 @@ return; python = strstr(headurl, "/python/"); - if (!python) - Py_FatalError("subversion keywords missing"); + if (!python) { + *patchlevel_revision = '\0'; + strcpy(branch, ""); + strcpy(shortbranch, "unknown"); + svn_revision = ""; + return; + } br_start = python + 8; br_end = strchr(br_start, '/'); From python-checkins at python.org Sun Apr 17 22:38:14 2011 From: python-checkins at python.org (martin.v.loewis) Date: Sun, 17 Apr 2011 22:38:14 +0200 (CEST) Subject: [Python-checkins] r88819 - in python/branches/release25-maint/Lib: urllib.py urllib2.py Message-ID: <3QCPZG1s93z7Ljf@mail.python.org> Author: martin.v.loewis Date: Sun Apr 17 22:38:14 2011 New Revision: 88819 Log: hg dd852a0f92d6 by guido at google.com Issue 22663: fix redirect vulnerability in urllib/urllib2. Modified: python/branches/release25-maint/Lib/urllib.py python/branches/release25-maint/Lib/urllib2.py Modified: python/branches/release25-maint/Lib/urllib.py ============================================================================== --- python/branches/release25-maint/Lib/urllib.py (original) +++ python/branches/release25-maint/Lib/urllib.py Sun Apr 17 22:38:14 2011 @@ -638,10 +638,19 @@ newurl = headers['uri'] else: return - void = fp.read() - fp.close() + # In case the server sent a relative URL, join with original: newurl = basejoin(self.type + ":" + url, newurl) + + # For security reasons we do not allow redirects to protocols + # other than HTTP or HTTPS. + newurl_lower = newurl.lower() + if not (newurl_lower.startswith('http://') or + newurl_lower.startswith('https://')): + return + + void = fp.read() + fp.close() return self.open(newurl) def http_error_301(self, url, fp, errcode, errmsg, headers, data=None): Modified: python/branches/release25-maint/Lib/urllib2.py ============================================================================== --- python/branches/release25-maint/Lib/urllib2.py (original) +++ python/branches/release25-maint/Lib/urllib2.py Sun Apr 17 22:38:14 2011 @@ -555,6 +555,13 @@ return newurl = urlparse.urljoin(req.get_full_url(), newurl) + # For security reasons we do not allow redirects to protocols + # other than HTTP or HTTPS. + newurl_lower = newurl.lower() + if not (newurl_lower.startswith('http://') or + newurl_lower.startswith('https://')): + return + # XXX Probably want to forget about the state of the current # request, although that might interact poorly with other # handlers that also use handler-specific request attributes From python-checkins at python.org Sun Apr 17 22:43:48 2011 From: python-checkins at python.org (martin.v.loewis) Date: Sun, 17 Apr 2011 22:43:48 +0200 (CEST) Subject: [Python-checkins] r88820 - in python/branches/release25-maint: Lib/urllib.py Lib/urllib2.py Misc/NEWS Message-ID: <3QCPhh3bQCz7Llp@mail.python.org> Author: martin.v.loewis Date: Sun Apr 17 22:43:47 2011 New Revision: 88820 Log: hg ca3b117c40f3 by guido at google.com Add FTP to the allowed url schemes. Add Misc/NEWS. Modified: python/branches/release25-maint/Lib/urllib.py python/branches/release25-maint/Lib/urllib2.py python/branches/release25-maint/Misc/NEWS Modified: python/branches/release25-maint/Lib/urllib.py ============================================================================== --- python/branches/release25-maint/Lib/urllib.py (original) +++ python/branches/release25-maint/Lib/urllib.py Sun Apr 17 22:43:47 2011 @@ -643,10 +643,11 @@ newurl = basejoin(self.type + ":" + url, newurl) # For security reasons we do not allow redirects to protocols - # other than HTTP or HTTPS. + # other than HTTP, HTTPS or FTP. newurl_lower = newurl.lower() if not (newurl_lower.startswith('http://') or - newurl_lower.startswith('https://')): + newurl_lower.startswith('https://') or + newurl_lower.startswith('ftp://')): return void = fp.read() Modified: python/branches/release25-maint/Lib/urllib2.py ============================================================================== --- python/branches/release25-maint/Lib/urllib2.py (original) +++ python/branches/release25-maint/Lib/urllib2.py Sun Apr 17 22:43:47 2011 @@ -556,10 +556,11 @@ newurl = urlparse.urljoin(req.get_full_url(), newurl) # For security reasons we do not allow redirects to protocols - # other than HTTP or HTTPS. + # other than HTTP, HTTPS or FTP. newurl_lower = newurl.lower() if not (newurl_lower.startswith('http://') or - newurl_lower.startswith('https://')): + newurl_lower.startswith('https://') or + newurl_lower.startswith('ftp://')): return # XXX Probably want to forget about the state of the current Modified: python/branches/release25-maint/Misc/NEWS ============================================================================== --- python/branches/release25-maint/Misc/NEWS (original) +++ python/branches/release25-maint/Misc/NEWS Sun Apr 17 22:43:47 2011 @@ -12,6 +12,9 @@ Library ------- +- Issue #11662: Make urllib and urllib2 ignore redirections if the + scheme is not HTTP, HTTPS or FTP. This fixes a security hole. + - Issue #8674: Fixed a number of incorrect or undefined-behaviour-inducing overflow checks in the audioop module (CVE-2010-1634). From python-checkins at python.org Sun Apr 17 22:44:50 2011 From: python-checkins at python.org (martin.v.loewis) Date: Sun, 17 Apr 2011 22:44:50 +0200 (CEST) Subject: [Python-checkins] r88821 - in python/branches/release25-maint/Lib: test/test_urllib.py test/test_urllib2.py urllib.py urllib2.py Message-ID: <3QCPjt18YWz7Ljf@mail.python.org> Author: martin.v.loewis Date: Sun Apr 17 22:44:49 2011 New Revision: 88821 Log: hg 9d06d5eb1a7e by guido at google.com Add tests for the urllib[2] vulnerability. Change to raise exceptions. Modified: python/branches/release25-maint/Lib/test/test_urllib.py python/branches/release25-maint/Lib/test/test_urllib2.py python/branches/release25-maint/Lib/urllib.py python/branches/release25-maint/Lib/urllib2.py Modified: python/branches/release25-maint/Lib/test/test_urllib.py ============================================================================== --- python/branches/release25-maint/Lib/test/test_urllib.py (original) +++ python/branches/release25-maint/Lib/test/test_urllib.py Sun Apr 17 22:44:49 2011 @@ -122,6 +122,20 @@ finally: self.unfakehttp() + def test_invalid_redirect(self): + # urlopen() should raise IOError for many error codes. + self.fakehttp("""HTTP/1.1 302 Found +Date: Wed, 02 Jan 2008 03:03:54 GMT +Server: Apache/1.3.33 (Debian GNU/Linux) mod_ssl/2.8.22 OpenSSL/0.9.7e +Location: file:README +Connection: close +Content-Type: text/html; charset=iso-8859-1 +""") + try: + self.assertRaises(IOError, urllib.urlopen, "http://python.org/") + finally: + self.unfakehttp() + def test_empty_socket(self): """urlopen() raises IOError if the underlying socket does not send any data. (#1680230) """ Modified: python/branches/release25-maint/Lib/test/test_urllib2.py ============================================================================== --- python/branches/release25-maint/Lib/test/test_urllib2.py (original) +++ python/branches/release25-maint/Lib/test/test_urllib2.py Sun Apr 17 22:44:49 2011 @@ -857,6 +857,27 @@ self.assertEqual(count, urllib2.HTTPRedirectHandler.max_redirections) + def test_invalid_redirect(self): + from_url = "http://example.com/a.html" + valid_schemes = ['http', 'https', 'ftp'] + invalid_schemes = ['file', 'imap', 'ldap'] + schemeless_url = "example.com/b.html" + h = urllib2.HTTPRedirectHandler() + o = h.parent = MockOpener() + req = Request(from_url) + + for scheme in invalid_schemes: + invalid_url = scheme + '://' + schemeless_url + self.assertRaises(urllib2.HTTPError, h.http_error_302, + req, MockFile(), 302, "Security Loophole", + MockHeaders({"location": invalid_url})) + + for scheme in valid_schemes: + valid_url = scheme + '://' + schemeless_url + h.http_error_302(req, MockFile(), 302, "That's fine", + MockHeaders({"location": valid_url})) + self.assertEqual(o.req.get_full_url(), valid_url) + def test_cookie_redirect(self): # cookies shouldn't leak into redirected requests from cookielib import CookieJar Modified: python/branches/release25-maint/Lib/urllib.py ============================================================================== --- python/branches/release25-maint/Lib/urllib.py (original) +++ python/branches/release25-maint/Lib/urllib.py Sun Apr 17 22:44:49 2011 @@ -638,7 +638,8 @@ newurl = headers['uri'] else: return - + void = fp.read() + fp.close() # In case the server sent a relative URL, join with original: newurl = basejoin(self.type + ":" + url, newurl) @@ -648,10 +649,11 @@ if not (newurl_lower.startswith('http://') or newurl_lower.startswith('https://') or newurl_lower.startswith('ftp://')): - return + raise IOError('redirect error', errcode, + errmsg + " - Redirection to url '%s' is not allowed" % + newurl, + headers) - void = fp.read() - fp.close() return self.open(newurl) def http_error_301(self, url, fp, errcode, errmsg, headers, data=None): Modified: python/branches/release25-maint/Lib/urllib2.py ============================================================================== --- python/branches/release25-maint/Lib/urllib2.py (original) +++ python/branches/release25-maint/Lib/urllib2.py Sun Apr 17 22:44:49 2011 @@ -561,7 +561,10 @@ if not (newurl_lower.startswith('http://') or newurl_lower.startswith('https://') or newurl_lower.startswith('ftp://')): - return + raise HTTPError(newurl, code, + msg + " - Redirection to url '%s' is not allowed" % + newurl, + headers, fp) # XXX Probably want to forget about the state of the current # request, although that might interact poorly with other From python-checkins at python.org Sun Apr 17 22:46:44 2011 From: python-checkins at python.org (martin.v.loewis) Date: Sun, 17 Apr 2011 22:46:44 +0200 (CEST) Subject: [Python-checkins] r88822 - python/branches/release25-maint/Misc/NEWS Message-ID: <3QCPm46HPHz7Lm5@mail.python.org> Author: martin.v.loewis Date: Sun Apr 17 22:46:44 2011 New Revision: 88822 Log: hg f03e2acb9826 by guido at google.com Add CVE number to urllib/urllib2 news item. Modified: python/branches/release25-maint/Misc/NEWS Modified: python/branches/release25-maint/Misc/NEWS ============================================================================== --- python/branches/release25-maint/Misc/NEWS (original) +++ python/branches/release25-maint/Misc/NEWS Sun Apr 17 22:46:44 2011 @@ -13,7 +13,7 @@ ------- - Issue #11662: Make urllib and urllib2 ignore redirections if the - scheme is not HTTP, HTTPS or FTP. This fixes a security hole. + scheme is not HTTP, HTTPS or FTP (CVE-2011-1521). - Issue #8674: Fixed a number of incorrect or undefined-behaviour-inducing overflow checks in the audioop module (CVE-2010-1634). From python-checkins at python.org Sun Apr 17 22:48:44 2011 From: python-checkins at python.org (martin.v.loewis) Date: Sun, 17 Apr 2011 22:48:44 +0200 (CEST) Subject: [Python-checkins] r88823 - python/branches/release25-maint/Misc/NEWS Message-ID: <3QCPpN6tw9z7Lm0@mail.python.org> Author: martin.v.loewis Date: Sun Apr 17 22:48:44 2011 New Revision: 88823 Log: hg bb1695c6cea1 by me Issue 11442: Add NEWS entry for e9724d7abbc2 Modified: python/branches/release25-maint/Misc/NEWS Modified: python/branches/release25-maint/Misc/NEWS ============================================================================== --- python/branches/release25-maint/Misc/NEWS (original) +++ python/branches/release25-maint/Misc/NEWS Sun Apr 17 22:48:44 2011 @@ -12,6 +12,9 @@ Library ------- +- Issue #11442: Add a charset parameter to the Content-type in SimpleHTTPServer + to avoid XSS attacks. + - Issue #11662: Make urllib and urllib2 ignore redirections if the scheme is not HTTP, HTTPS or FTP (CVE-2011-1521). From python-checkins at python.org Sun Apr 17 23:01:35 2011 From: python-checkins at python.org (martin.v.loewis) Date: Sun, 17 Apr 2011 23:01:35 +0200 Subject: [Python-checkins] cpython (2.5): Issue 11442: Add NEWS entry for e9724d7abbc2 Message-ID: http://hg.python.org/cpython/rev/bb1695c6cea1 changeset: 69409:bb1695c6cea1 branch: 2.5 parent: 69044:92293101839c user: Martin v. L?wis date: Sun Apr 17 22:29:40 2011 +0200 summary: Issue 11442: Add NEWS entry for e9724d7abbc2 files: Misc/NEWS | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -12,6 +12,9 @@ Library ------- +- Issue #11442: Add a charset parameter to the Content-type in SimpleHTTPServer + to avoid XSS attacks. + - Issue #11662: Make urllib and urllib2 ignore redirections if the scheme is not HTTP, HTTPS or FTP (CVE-2011-1521). -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Apr 17 23:01:37 2011 From: python-checkins at python.org (martin.v.loewis) Date: Sun, 17 Apr 2011 23:01:37 +0200 Subject: [Python-checkins] cpython (merge 2.5 -> 2.6): merge 11442 NEWS Message-ID: http://hg.python.org/cpython/rev/4bd47815e6c5 changeset: 69410:4bd47815e6c5 branch: 2.6 parent: 69056:202078f2856f parent: 69409:bb1695c6cea1 user: Martin v. L?wis date: Sun Apr 17 22:56:19 2011 +0200 summary: merge 11442 NEWS files: Misc/NEWS | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -19,6 +19,9 @@ Library ------- +- Issue #11442: Add a charset parameter to the Content-type in SimpleHTTPServer + to avoid XSS attacks. + - Issue #11662: Make urllib and urllib2 ignore redirections if the scheme is not HTTP, HTTPS or FTP (CVE-2011-1521). -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Apr 17 23:01:43 2011 From: python-checkins at python.org (martin.v.loewis) Date: Sun, 17 Apr 2011 23:01:43 +0200 Subject: [Python-checkins] cpython (merge 2.6 -> 2.7): merge 11442 NEWS Message-ID: http://hg.python.org/cpython/rev/d683ff1d6866 changeset: 69411:d683ff1d6866 branch: 2.7 parent: 69406:cc65cf9a9ce5 parent: 69410:4bd47815e6c5 user: Martin v. L?wis date: Sun Apr 17 23:01:13 2011 +0200 summary: merge 11442 NEWS files: Misc/NEWS | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -55,6 +55,9 @@ Library ------- +- Issue #11442: Add a charset parameter to the Content-type in SimpleHTTPServer + to avoid XSS attacks. + - Issue #11467: Fix urlparse behavior when handling urls which contains scheme specific part only digits. Patch by Santoso Wijaya. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Apr 17 23:15:32 2011 From: python-checkins at python.org (martin.v.loewis) Date: Sun, 17 Apr 2011 23:15:32 +0200 (CEST) Subject: [Python-checkins] r88824 - in python/branches/release25-maint: Include/patchlevel.h Lib/idlelib/NEWS.txt Lib/idlelib/idlever.py Misc/NEWS README Message-ID: <3QCQPJ2WXVz7LjT@mail.python.org> Author: martin.v.loewis Date: Sun Apr 17 23:15:32 2011 New Revision: 88824 Log: Prepare for 2.5.6c1. Modified: python/branches/release25-maint/Include/patchlevel.h python/branches/release25-maint/Lib/idlelib/NEWS.txt python/branches/release25-maint/Lib/idlelib/idlever.py python/branches/release25-maint/Misc/NEWS python/branches/release25-maint/README Modified: python/branches/release25-maint/Include/patchlevel.h ============================================================================== --- python/branches/release25-maint/Include/patchlevel.h (original) +++ python/branches/release25-maint/Include/patchlevel.h Sun Apr 17 23:15:32 2011 @@ -22,11 +22,11 @@ #define PY_MAJOR_VERSION 2 #define PY_MINOR_VERSION 5 #define PY_MICRO_VERSION 6 -#define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_ALPHA -#define PY_RELEASE_SERIAL 0 +#define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_GAMMA +#define PY_RELEASE_SERIAL 1 /* Version as a string */ -#define PY_VERSION "2.5.5+" +#define PY_VERSION "2.5.6c1" /* Subversion Revision number of this file (not of the repository) */ #define PY_PATCHLEVEL_REVISION "$Revision$" Modified: python/branches/release25-maint/Lib/idlelib/NEWS.txt ============================================================================== --- python/branches/release25-maint/Lib/idlelib/NEWS.txt (original) +++ python/branches/release25-maint/Lib/idlelib/NEWS.txt Sun Apr 17 23:15:32 2011 @@ -1,3 +1,8 @@ +What's New in IDLE 1.2.6c1? +=========================== + +*Release date: 17-Apr-2011* + What's New in IDLE 1.2.5? ========================= Modified: python/branches/release25-maint/Lib/idlelib/idlever.py ============================================================================== --- python/branches/release25-maint/Lib/idlelib/idlever.py (original) +++ python/branches/release25-maint/Lib/idlelib/idlever.py Sun Apr 17 23:15:32 2011 @@ -1 +1 @@ -IDLE_VERSION = "1.2.5" +IDLE_VERSION = "1.2.6c1" Modified: python/branches/release25-maint/Misc/NEWS ============================================================================== --- python/branches/release25-maint/Misc/NEWS (original) +++ python/branches/release25-maint/Misc/NEWS Sun Apr 17 23:15:32 2011 @@ -7,7 +7,7 @@ What's New in Python 2.5.6c1? ============================= -*Release date: XX-XXX-2010* +*Release date: 17-Apr-2010* Library ------- Modified: python/branches/release25-maint/README ============================================================================== --- python/branches/release25-maint/README (original) +++ python/branches/release25-maint/README Sun Apr 17 23:15:32 2011 @@ -1,5 +1,5 @@ -This is Python version 2.5.5 -============================ +This is Python version 2.5.6c1 +============================== Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Python Software Foundation. All rights reserved. From python-checkins at python.org Sun Apr 17 23:25:52 2011 From: python-checkins at python.org (martin.v.loewis) Date: Sun, 17 Apr 2011 23:25:52 +0200 (CEST) Subject: [Python-checkins] r88825 - sandbox/trunk/welease/welease.py Message-ID: <3QCQdD48rjz7LmF@mail.python.org> Author: martin.v.loewis Date: Sun Apr 17 23:25:52 2011 New Revision: 88825 Log: Work around 2.6.6 bug. Modified: sandbox/trunk/welease/welease.py Modified: sandbox/trunk/welease/welease.py ============================================================================== --- sandbox/trunk/welease/welease.py (original) +++ sandbox/trunk/welease/welease.py Sun Apr 17 23:25:52 2011 @@ -660,4 +660,6 @@ # End config if __name__ == "__main__": + # issue 7980 + time.strptime('','') main() From python-checkins at python.org Sun Apr 17 23:27:16 2011 From: python-checkins at python.org (martin.v.loewis) Date: Sun, 17 Apr 2011 23:27:16 +0200 (CEST) Subject: [Python-checkins] r88826 - python/tags/r256c1 Message-ID: <3QCQfr5xKQz7Lkh@mail.python.org> Author: martin.v.loewis Date: Sun Apr 17 23:27:16 2011 New Revision: 88826 Log: Tagging for release of Python 2.5.6c1 Added: python/tags/r256c1/ - copied from r88825, /python/branches/release25-maint/ From python-checkins at python.org Mon Apr 18 00:36:34 2011 From: python-checkins at python.org (martin.v.loewis) Date: Mon, 18 Apr 2011 00:36:34 +0200 (CEST) Subject: [Python-checkins] r88827 - sandbox/trunk/welease/welease.py Message-ID: <3QCSBp5Cmlz7Ljf@mail.python.org> Author: martin.v.loewis Date: Mon Apr 18 00:36:27 2011 New Revision: 88827 Log: Stop checking MSI uuids. Modified: sandbox/trunk/welease/welease.py Modified: sandbox/trunk/welease/welease.py ============================================================================== --- sandbox/trunk/welease/welease.py (original) +++ sandbox/trunk/welease/welease.py Mon Apr 18 00:36:27 2011 @@ -546,6 +546,8 @@ return dd def checkMsiFileForVersion(dirname, version): + # we don't do windows releases anymore with this tool + return 0 if os.path.exists(os.path.join(dirname, 'uuids.py')): sys.path.insert(0, dirname) from uuids import product_codes From python-checkins at python.org Mon Apr 18 04:50:10 2011 From: python-checkins at python.org (raymond.hettinger) Date: Mon, 18 Apr 2011 04:50:10 +0200 Subject: [Python-checkins] cpython (3.1): Rework multiset methods to use less memory and to make fewer calls to __hash__. Message-ID: http://hg.python.org/cpython/rev/49e756c8c08b changeset: 69412:49e756c8c08b branch: 3.1 parent: 69395:ff735436c247 user: Raymond Hettinger date: Sun Apr 17 19:46:46 2011 -0700 summary: Rework multiset methods to use less memory and to make fewer calls to __hash__. files: Lib/collections.py | 31 +++++++++++++++++++------------ 1 files changed, 19 insertions(+), 12 deletions(-) diff --git a/Lib/collections.py b/Lib/collections.py --- a/Lib/collections.py +++ b/Lib/collections.py @@ -495,10 +495,13 @@ if not isinstance(other, Counter): return NotImplemented result = Counter() - for elem in set(self) | set(other): - newcount = self[elem] + other[elem] + for elem, count in self.items(): + newcount = count + other[elem] if newcount > 0: result[elem] = newcount + for elem, count in other.items(): + if elem not in self and count > 0: + result[elem] = count return result def __sub__(self, other): @@ -511,10 +514,13 @@ if not isinstance(other, Counter): return NotImplemented result = Counter() - for elem in set(self) | set(other): - newcount = self[elem] - other[elem] + for elem, count in self.items(): + newcount = count - other[elem] if newcount > 0: result[elem] = newcount + for elem, count in other.items(): + if elem not in self and count < 0: + result[elem] = 0 - count return result def __or__(self, other): @@ -527,11 +533,14 @@ if not isinstance(other, Counter): return NotImplemented result = Counter() - for elem in set(self) | set(other): - p, q = self[elem], other[elem] - newcount = q if p < q else p + for elem, count in self.items(): + other_count = other[elem] + newcount = other_count if count < other_count else count if newcount > 0: result[elem] = newcount + for elem, count in other.items(): + if elem not in self and count > 0: + result[elem] = count return result def __and__(self, other): @@ -544,11 +553,9 @@ if not isinstance(other, Counter): return NotImplemented result = Counter() - if len(self) < len(other): - self, other = other, self - for elem in filter(self.__contains__, other): - p, q = self[elem], other[elem] - newcount = p if p < q else q + for elem, count in self.items(): + other_count = other[elem] + newcount = count if count < other_count else other_count if newcount > 0: result[elem] = newcount return result -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 18 04:50:11 2011 From: python-checkins at python.org (raymond.hettinger) Date: Mon, 18 Apr 2011 04:50:11 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): Rework multiset methods to use less memory and to make fewer calls to __hash__. Message-ID: http://hg.python.org/cpython/rev/76fb918f98dd changeset: 69413:76fb918f98dd branch: 3.2 parent: 69407:fcce2f49ef6d parent: 69412:49e756c8c08b user: Raymond Hettinger date: Sun Apr 17 19:47:24 2011 -0700 summary: Rework multiset methods to use less memory and to make fewer calls to __hash__. files: Lib/collections.py | 31 +++++++++++++++++++------------ 1 files changed, 19 insertions(+), 12 deletions(-) diff --git a/Lib/collections.py b/Lib/collections.py --- a/Lib/collections.py +++ b/Lib/collections.py @@ -572,10 +572,13 @@ if not isinstance(other, Counter): return NotImplemented result = Counter() - for elem in set(self) | set(other): - newcount = self[elem] + other[elem] + for elem, count in self.items(): + newcount = count + other[elem] if newcount > 0: result[elem] = newcount + for elem, count in other.items(): + if elem not in self and count > 0: + result[elem] = count return result def __sub__(self, other): @@ -588,10 +591,13 @@ if not isinstance(other, Counter): return NotImplemented result = Counter() - for elem in set(self) | set(other): - newcount = self[elem] - other[elem] + for elem, count in self.items(): + newcount = count - other[elem] if newcount > 0: result[elem] = newcount + for elem, count in other.items(): + if elem not in self and count < 0: + result[elem] = 0 - count return result def __or__(self, other): @@ -604,11 +610,14 @@ if not isinstance(other, Counter): return NotImplemented result = Counter() - for elem in set(self) | set(other): - p, q = self[elem], other[elem] - newcount = q if p < q else p + for elem, count in self.items(): + other_count = other[elem] + newcount = other_count if count < other_count else count if newcount > 0: result[elem] = newcount + for elem, count in other.items(): + if elem not in self and count > 0: + result[elem] = count return result def __and__(self, other): @@ -621,11 +630,9 @@ if not isinstance(other, Counter): return NotImplemented result = Counter() - if len(self) < len(other): - self, other = other, self - for elem in filter(self.__contains__, other): - p, q = self[elem], other[elem] - newcount = p if p < q else q + for elem, count in self.items(): + other_count = other[elem] + newcount = count if count < other_count else other_count if newcount > 0: result[elem] = newcount return result -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 18 04:50:11 2011 From: python-checkins at python.org (raymond.hettinger) Date: Mon, 18 Apr 2011 04:50:11 +0200 Subject: [Python-checkins] cpython: Rework multiset methods to use less memory and to make fewer calls to __hash__. Message-ID: http://hg.python.org/cpython/rev/e908ebc160f0 changeset: 69414:e908ebc160f0 parent: 69408:c33596e6f723 user: Raymond Hettinger date: Sun Apr 17 19:49:29 2011 -0700 summary: Rework multiset methods to use less memory and to make fewer calls to __hash__. files: Lib/collections/__init__.py | 31 +++++++++++++++--------- 1 files changed, 19 insertions(+), 12 deletions(-) diff --git a/Lib/collections/__init__.py b/Lib/collections/__init__.py --- a/Lib/collections/__init__.py +++ b/Lib/collections/__init__.py @@ -601,10 +601,13 @@ if not isinstance(other, Counter): return NotImplemented result = Counter() - for elem in set(self) | set(other): - newcount = self[elem] + other[elem] + for elem, count in self.items(): + newcount = count + other[elem] if newcount > 0: result[elem] = newcount + for elem, count in other.items(): + if elem not in self and count > 0: + result[elem] = count return result def __sub__(self, other): @@ -617,10 +620,13 @@ if not isinstance(other, Counter): return NotImplemented result = Counter() - for elem in set(self) | set(other): - newcount = self[elem] - other[elem] + for elem, count in self.items(): + newcount = count - other[elem] if newcount > 0: result[elem] = newcount + for elem, count in other.items(): + if elem not in self and count < 0: + result[elem] = 0 - count return result def __or__(self, other): @@ -633,11 +639,14 @@ if not isinstance(other, Counter): return NotImplemented result = Counter() - for elem in set(self) | set(other): - p, q = self[elem], other[elem] - newcount = q if p < q else p + for elem, count in self.items(): + other_count = other[elem] + newcount = other_count if count < other_count else count if newcount > 0: result[elem] = newcount + for elem, count in other.items(): + if elem not in self and count > 0: + result[elem] = count return result def __and__(self, other): @@ -650,11 +659,9 @@ if not isinstance(other, Counter): return NotImplemented result = Counter() - if len(self) < len(other): - self, other = other, self - for elem in filter(self.__contains__, other): - p, q = self[elem], other[elem] - newcount = p if p < q else q + for elem, count in self.items(): + other_count = other[elem] + newcount = count if count < other_count else other_count if newcount > 0: result[elem] = newcount return result -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 18 04:50:13 2011 From: python-checkins at python.org (raymond.hettinger) Date: Mon, 18 Apr 2011 04:50:13 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): merge Message-ID: http://hg.python.org/cpython/rev/ac563fba7161 changeset: 69415:ac563fba7161 parent: 69414:e908ebc160f0 parent: 69413:76fb918f98dd user: Raymond Hettinger date: Sun Apr 17 19:49:58 2011 -0700 summary: merge files: -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Mon Apr 18 05:00:20 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Mon, 18 Apr 2011 05:00:20 +0200 Subject: [Python-checkins] Daily reference leaks (c33596e6f723): sum=-56 Message-ID: results for c33596e6f723 on branch "default" -------------------------------------------- test_pyexpat leaked [0, 0, -56] references, sum=-56 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflog3wpISO', '-x'] From python-checkins at python.org Mon Apr 18 05:08:49 2011 From: python-checkins at python.org (raymond.hettinger) Date: Mon, 18 Apr 2011 05:08:49 +0200 Subject: [Python-checkins] cpython (2.7): Rework multiset methods to use less memory and to make fewer calls to __hash__. Message-ID: http://hg.python.org/cpython/rev/0c7ea87f676a changeset: 69416:0c7ea87f676a branch: 2.7 parent: 69411:d683ff1d6866 user: Raymond Hettinger date: Sun Apr 17 20:08:41 2011 -0700 summary: Rework multiset methods to use less memory and to make fewer calls to __hash__. files: Lib/collections.py | 31 +++++++++++++++++++------------ 1 files changed, 19 insertions(+), 12 deletions(-) diff --git a/Lib/collections.py b/Lib/collections.py --- a/Lib/collections.py +++ b/Lib/collections.py @@ -552,10 +552,13 @@ if not isinstance(other, Counter): return NotImplemented result = Counter() - for elem in set(self) | set(other): - newcount = self[elem] + other[elem] + for elem, count in self.items(): + newcount = count + other[elem] if newcount > 0: result[elem] = newcount + for elem, count in other.items(): + if elem not in self and count > 0: + result[elem] = count return result def __sub__(self, other): @@ -568,10 +571,13 @@ if not isinstance(other, Counter): return NotImplemented result = Counter() - for elem in set(self) | set(other): - newcount = self[elem] - other[elem] + for elem, count in self.items(): + newcount = count - other[elem] if newcount > 0: result[elem] = newcount + for elem, count in other.items(): + if elem not in self and count < 0: + result[elem] = 0 - count return result def __or__(self, other): @@ -584,11 +590,14 @@ if not isinstance(other, Counter): return NotImplemented result = Counter() - for elem in set(self) | set(other): - p, q = self[elem], other[elem] - newcount = q if p < q else p + for elem, count in self.items(): + other_count = other[elem] + newcount = other_count if count < other_count else count if newcount > 0: result[elem] = newcount + for elem, count in other.items(): + if elem not in self and count > 0: + result[elem] = count return result def __and__(self, other): @@ -601,11 +610,9 @@ if not isinstance(other, Counter): return NotImplemented result = Counter() - if len(self) < len(other): - self, other = other, self - for elem in _ifilter(self.__contains__, other): - p, q = self[elem], other[elem] - newcount = p if p < q else q + for elem, count in self.items(): + other_count = other[elem] + newcount = count if count < other_count else other_count if newcount > 0: result[elem] = newcount return result -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 18 07:24:19 2011 From: python-checkins at python.org (martin.v.loewis) Date: Mon, 18 Apr 2011 07:24:19 +0200 (CEST) Subject: [Python-checkins] r88828 - python/branches/release25-maint/Misc/NEWS Message-ID: <3QCdFH07HGz7LjT@mail.python.org> Author: martin.v.loewis Date: Mon Apr 18 07:24:18 2011 New Revision: 88828 Log: Fix year. Modified: python/branches/release25-maint/Misc/NEWS Modified: python/branches/release25-maint/Misc/NEWS ============================================================================== --- python/branches/release25-maint/Misc/NEWS (original) +++ python/branches/release25-maint/Misc/NEWS Mon Apr 18 07:24:18 2011 @@ -7,7 +7,7 @@ What's New in Python 2.5.6c1? ============================= -*Release date: 17-Apr-2010* +*Release date: 17-Apr-2011* Library ------- From python-checkins at python.org Mon Apr 18 09:15:10 2011 From: python-checkins at python.org (ezio.melotti) Date: Mon, 18 Apr 2011 09:15:10 +0200 Subject: [Python-checkins] cpython (2.7): #11865: fix typo in init.rst. Message-ID: http://hg.python.org/cpython/rev/fc2def15ab11 changeset: 69417:fc2def15ab11 branch: 2.7 user: Ezio Melotti date: Mon Apr 18 10:11:21 2011 +0300 summary: #11865: fix typo in init.rst. files: Doc/c-api/init.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -906,7 +906,7 @@ main thread where it has possession of the global interpreter lock and can perform any Python API calls. -.. cfunction:: void Py_AddPendingCall( int (*func)(void *, void *arg) ) +.. cfunction:: void Py_AddPendingCall(int (*func)(void *), void *arg) .. index:: single: Py_AddPendingCall() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 18 09:15:11 2011 From: python-checkins at python.org (ezio.melotti) Date: Mon, 18 Apr 2011 09:15:11 +0200 Subject: [Python-checkins] cpython (3.1): #11865: fix typo in init.rst. Message-ID: http://hg.python.org/cpython/rev/6e090d78857c changeset: 69418:6e090d78857c branch: 3.1 parent: 69412:49e756c8c08b user: Ezio Melotti date: Mon Apr 18 10:11:21 2011 +0300 summary: #11865: fix typo in init.rst. files: Doc/c-api/init.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -892,7 +892,7 @@ main thread where it has possession of the global interpreter lock and can perform any Python API calls. -.. cfunction:: void Py_AddPendingCall( int (*func)(void *, void *arg) ) +.. cfunction:: void Py_AddPendingCall(int (*func)(void *), void *arg) .. index:: single: Py_AddPendingCall() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 18 09:15:13 2011 From: python-checkins at python.org (ezio.melotti) Date: Mon, 18 Apr 2011 09:15:13 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): #11865: Merge with 3.1. Message-ID: http://hg.python.org/cpython/rev/ce804653c752 changeset: 69419:ce804653c752 branch: 3.2 parent: 69413:76fb918f98dd parent: 69418:6e090d78857c user: Ezio Melotti date: Mon Apr 18 10:14:13 2011 +0300 summary: #11865: Merge with 3.1. files: Doc/c-api/init.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -908,7 +908,7 @@ main thread where it has possession of the global interpreter lock and can perform any Python API calls. -.. c:function:: void Py_AddPendingCall( int (*func)(void *, void *arg) ) +.. c:function:: void Py_AddPendingCall(int (*func)(void *), void *arg) .. index:: single: Py_AddPendingCall() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 18 09:15:21 2011 From: python-checkins at python.org (ezio.melotti) Date: Mon, 18 Apr 2011 09:15:21 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): #11865: Merge with 3.2. Message-ID: http://hg.python.org/cpython/rev/d8dd02f6db1a changeset: 69420:d8dd02f6db1a parent: 69415:ac563fba7161 parent: 69419:ce804653c752 user: Ezio Melotti date: Mon Apr 18 10:14:49 2011 +0300 summary: #11865: Merge with 3.2. files: Doc/c-api/init.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -908,7 +908,7 @@ main thread where it has possession of the global interpreter lock and can perform any Python API calls. -.. c:function:: void Py_AddPendingCall( int (*func)(void *, void *arg) ) +.. c:function:: void Py_AddPendingCall(int (*func)(void *), void *arg) .. index:: single: Py_AddPendingCall() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 18 16:12:28 2011 From: python-checkins at python.org (r.david.murray) Date: Mon, 18 Apr 2011 16:12:28 +0200 Subject: [Python-checkins] cpython (3.2): #11492: rewrite header folding algorithm. Less code, more passing tests. Message-ID: http://hg.python.org/cpython/rev/51a551acb60d changeset: 69421:51a551acb60d branch: 3.2 parent: 69419:ce804653c752 user: R David Murray date: Mon Apr 18 10:04:34 2011 -0400 summary: #11492: rewrite header folding algorithm. Less code, more passing tests. files: Doc/library/email.header.rst | 14 +- Lib/email/header.py | 285 ++++++++-------------- Lib/email/test/test_email.py | 149 ++++++++++- Misc/NEWS | 2 + 4 files changed, 252 insertions(+), 198 deletions(-) diff --git a/Doc/library/email.header.rst b/Doc/library/email.header.rst --- a/Doc/library/email.header.rst +++ b/Doc/library/email.header.rst @@ -109,9 +109,17 @@ Encode a message header into an RFC-compliant format, possibly wrapping long lines and encapsulating non-ASCII parts in base64 or quoted-printable - encodings. Optional *splitchars* is a string containing characters to - split long ASCII lines on, in rough support of :rfc:`2822`'s *highest - level syntactic breaks*. This doesn't affect :rfc:`2047` encoded lines. + encodings. + + Optional *splitchars* is a string containing characters which should be + given extra weight by the splitting algorithm during normal header + wrapping. This is in very rough support of :RFC:`2822`\'s 'higher level + syntactic breaks': split points preceded by a splitchar are preferred + during line splitting, with the characters preferred in the order in + which they appear in the string. Space and tab may be included in the + string to indicate whether preference should be given to one over the + other as a split point when other split chars do not appear in the line + being split. Splitchars does not affect RFC 2047 encoded lines. *maxlinelen*, if given, overrides the instance's value for the maximum line length. diff --git a/Lib/email/header.py b/Lib/email/header.py --- a/Lib/email/header.py +++ b/Lib/email/header.py @@ -26,6 +26,7 @@ SPACE8 = ' ' * 8 EMPTYSTRING = '' MAXLINELEN = 78 +FWS = ' \t' USASCII = Charset('us-ascii') UTF8 = Charset('utf-8') @@ -299,9 +300,15 @@ name was specified at Header construction time. The default value for maxlinelen is determined at header construction time. - Optional splitchars is a string containing characters to split long - ASCII lines on, in rough support of RFC 2822's `highest level - syntactic breaks'. This doesn't affect RFC 2047 encoded lines. + Optional splitchars is a string containing characters which should be + given extra weight by the splitting algorithm during normal header + wrapping. This is in very rough support of RFC 2822's `higher level + syntactic breaks': split points preceded by a splitchar are preferred + during line splitting, with the characters preferred in the order in + which they appear in the string. Space and tab may be included in the + string to indicate whether preference should be given to one over the + other as a split point when other split chars do not appear in the line + being split. Splitchars does not affect RFC 2047 encoded lines. Optional linesep is a string to be used to separate the lines of the value. The default value is the most useful for typical @@ -320,13 +327,19 @@ self._continuation_ws, splitchars) for string, charset in self._chunks: lines = string.splitlines() - formatter.feed(lines[0] if lines else '', charset) + if lines: + formatter.feed('', lines[0], charset) + else: + formatter.feed('', '', charset) for line in lines[1:]: formatter.newline() if charset.header_encoding is not None: - formatter.feed(self._continuation_ws, USASCII) - line = ' ' + line.lstrip() - formatter.feed(line, charset) + formatter.feed(self._continuation_ws, ' ' + line.lstrip(), + charset) + else: + sline = line.lstrip() + fws = line[:len(line)-len(sline)] + formatter.feed(fws, sline, charset) if len(lines) > 1: formatter.newline() formatter.add_transition() @@ -360,7 +373,7 @@ def __init__(self, headerlen, maxlen, continuation_ws, splitchars): self._maxlen = maxlen self._continuation_ws = continuation_ws - self._continuation_ws_len = len(continuation_ws.replace('\t', SPACE8)) + self._continuation_ws_len = len(continuation_ws) self._splitchars = splitchars self._lines = [] self._current_line = _Accumulator(headerlen) @@ -374,43 +387,26 @@ def newline(self): end_of_line = self._current_line.pop() - if end_of_line is not None: - self._current_line.push(end_of_line) + if end_of_line != (' ', ''): + self._current_line.push(*end_of_line) if len(self._current_line) > 0: - self._lines.append(str(self._current_line)) + if self._current_line.is_onlyws(): + self._lines[-1] += str(self._current_line) + else: + self._lines.append(str(self._current_line)) self._current_line.reset() def add_transition(self): - self._current_line.push(None) + self._current_line.push(' ', '') - def feed(self, string, charset): - # If the string itself fits on the current line in its encoded format, - # then add it now and be done with it. - encoded_string = charset.header_encode(string) - if len(encoded_string) + len(self._current_line) <= self._maxlen: - self._current_line.push(encoded_string) - return + def feed(self, fws, string, charset): # If the charset has no header encoding (i.e. it is an ASCII encoding) # then we must split the header at the "highest level syntactic break" # possible. Note that we don't have a lot of smarts about field # syntax; we just try to break on semi-colons, then commas, then # whitespace. Eventually, this should be pluggable. if charset.header_encoding is None: - for ch in self._splitchars: - if ch in string: - break - else: - ch = None - # If there's no available split character then regardless of - # whether the string fits on the line, we have to put it on a line - # by itself. - if ch is None: - if not self._current_line.is_onlyws(): - self._lines.append(str(self._current_line)) - self._current_line.reset(self._continuation_ws) - self._current_line.push(encoded_string) - else: - self._ascii_split(string, ch) + self._ascii_split(fws, string, self._splitchars) return # Otherwise, we're doing either a Base64 or a quoted-printable # encoding which means we don't need to split the line on syntactic @@ -428,15 +424,14 @@ # There are no encoded lines, so we're done. return if first_line is not None: - self._current_line.push(first_line) - self._lines.append(str(self._current_line)) - self._current_line.reset(self._continuation_ws) + self._append_chunk(fws, first_line) try: last_line = encoded_lines.pop() except IndexError: # There was only one line. return - self._current_line.push(last_line) + self.newline() + self._current_line.push(self._continuation_ws, last_line) # Everything else are full lines in themselves. for line in encoded_lines: self._lines.append(self._continuation_ws + line) @@ -447,162 +442,96 @@ while True: yield self._maxlen - self._continuation_ws_len - def _ascii_split(self, string, ch): - holding = _Accumulator() - # Split the line on the split character, preserving it. If the split - # character is whitespace RFC 2822 $2.2.3 requires us to fold on the - # whitespace, so that the line leads with the original whitespace we - # split on. However, if a higher syntactic break is used instead - # (e.g. comma or semicolon), the folding should happen after the split - # character. But then in that case, we need to add our own - # continuation whitespace -- although won't that break unfolding? - for part, splitpart, nextpart in _spliterator(ch, string): - if not splitpart: - # No splitpart means this is the last chunk. Put this part - # either on the current line or the next line depending on - # whether it fits. - holding.push(part) - if len(holding) + len(self._current_line) <= self._maxlen: - # It fits, but we're done. - self._current_line.push(str(holding)) + def _ascii_split(self, fws, string, splitchars): + # The RFC 2822 header folding algorithm is simple in principle but + # complex in practice. Lines may be folded any place where "folding + # white space" appears by inserting a linesep character in front of the + # FWS. The complication is that not all spaces or tabs qualify as FWS, + # and we are also supposed to prefer to break at "higher level + # syntactic breaks". We can't do either of these without intimate + # knowledge of the structure of structured headers, which we don't have + # here. So the best we can do here is prefer to break at the specified + # splitchars, and hope that we don't choose any spaces or tabs that + # aren't legal FWS. (This is at least better than the old algorithm, + # where we would sometimes *introduce* FWS after a splitchar, or the + # algorithm before that, where we would turn all white space runs into + # single spaces or tabs.) + parts = re.split("(["+FWS+"]+)", fws+string) + if parts[0]: + parts[:0] = [''] + else: + parts.pop(0) + for fws, part in zip(*[iter(parts)]*2): + self._append_chunk(fws, part) + + def _append_chunk(self, fws, string): + self._current_line.push(fws, string) + if len(self._current_line) > self._maxlen: + # Find the best split point, working backward from the end. + # There might be none, on a long first line. + for ch in self._splitchars: + for i in range(self._current_line.part_count()-1, 0, -1): + if ch.isspace(): + fws = self._current_line[i][0] + if fws and fws[0]==ch: + break + prevpart = self._current_line[i-1][1] + if prevpart and prevpart[-1]==ch: + break else: - # It doesn't fit, but we're done. Before pushing a new - # line, watch out for the current line containing only - # whitespace. - holding.pop() - if self._current_line.is_onlyws() and holding.is_onlyws(): - # Don't start a new line. - holding.push(part) - part = None - self._current_line.push(str(holding)) - self._lines.append(str(self._current_line)) - if part is None: - self._current_line.reset() - else: - holding.reset(part) - self._current_line.reset(str(holding)) + continue + break + else: + fws, part = self._current_line.pop() + if self._current_line._initial_size > 0: + # There will be a header, so leave it on a line by itself. + self.newline() + if not fws: + # We don't use continuation_ws here because the whitespace + # after a header should always be a space. + fws = ' ' + self._current_line.push(fws, part) return - elif not nextpart: - # There must be some trailing or duplicated split characters - # because we - # found a split character but no next part. In this case we - # must treat the thing to fit as the part + splitpart because - # if splitpart is whitespace it's not allowed to be the only - # thing on the line, and if it's not whitespace we must split - # after the syntactic break. - holding_prelen = len(holding) - holding.push(part + splitpart) - if len(holding) + len(self._current_line) <= self._maxlen: - self._current_line.push(str(holding)) - elif holding_prelen == 0: - # This is the only chunk left so it has to go on the - # current line. - self._current_line.push(str(holding)) - else: - save_part = holding.pop() - self._current_line.push(str(holding)) - self._lines.append(str(self._current_line)) - holding.reset(save_part) - self._current_line.reset(str(holding)) - holding.reset() - elif not part: - # We're leading with a split character. See if the splitpart - # and nextpart fits on the current line. - holding.push(splitpart + nextpart) - holding_len = len(holding) - # We know we're not leaving the nextpart on the stack. - holding.pop() - if holding_len + len(self._current_line) <= self._maxlen: - holding.push(splitpart) - else: - # It doesn't fit. Since there's no current part really - # the best we can do is start a new line and push the - # split part onto it. - self._current_line.push(str(holding)) - holding.reset() - if len(self._current_line) > 0 and self._lines: - self._lines.append(str(self._current_line)) - self._current_line.reset() - holding.push(splitpart) - else: - # All three parts are present. First let's see if all three - # parts will fit on the current line. If so, we don't need to - # split it. - holding.push(part + splitpart + nextpart) - holding_len = len(holding) - # Pop the part because we'll push nextpart on the next - # iteration through the loop. - holding.pop() - if holding_len + len(self._current_line) <= self._maxlen: - holding.push(part + splitpart) - else: - # The entire thing doesn't fit. See if we need to split - # before or after the split characters. - if splitpart.isspace(): - # Split before whitespace. Remember that the - # whitespace becomes the continuation whitespace of - # the next line so it goes to current_line not holding. - holding.push(part) - self._current_line.push(str(holding)) - holding.reset() - self._lines.append(str(self._current_line)) - self._current_line.reset(splitpart) - else: - # Split after non-whitespace. The continuation - # whitespace comes from the instance variable. - holding.push(part + splitpart) - self._current_line.push(str(holding)) - holding.reset() - self._lines.append(str(self._current_line)) - if nextpart[0].isspace(): - self._current_line.reset() - else: - self._current_line.reset(self._continuation_ws) - # Get the last of the holding part - self._current_line.push(str(holding)) + remainder = self._current_line.pop_from(i) + self._lines.append(str(self._current_line)) + self._current_line.reset(remainder) - -def _spliterator(character, string): - parts = list(reversed(re.split('(%s)' % character, string))) - while parts: - part = parts.pop() - splitparts = (parts.pop() if parts else None) - nextpart = (parts.pop() if parts else None) - yield (part, splitparts, nextpart) - if nextpart is not None: - parts.append(nextpart) +class _Accumulator(list): - -class _Accumulator: def __init__(self, initial_size=0): self._initial_size = initial_size - self._current = [] + super().__init__() - def push(self, string): - self._current.append(string) + def push(self, fws, string): + self.append((fws, string)) + + def pop_from(self, i=0): + popped = self[i:] + self[i:] = [] + return popped def pop(self): - if not self._current: - return None - return self._current.pop() + if self.part_count()==0: + return ('', '') + return super().pop() def __len__(self): - return sum(((1 if string is None else len(string)) - for string in self._current), + return sum((len(fws)+len(part) for fws, part in self), self._initial_size) def __str__(self): - if self._current and self._current[-1] is None: - self._current.pop() - return EMPTYSTRING.join((' ' if string is None else string) - for string in self._current) + return EMPTYSTRING.join((EMPTYSTRING.join((fws, part)) + for fws, part in self)) - def reset(self, string=None): - self._current = [] + def reset(self, startval=None): + if startval is None: + startval = [] + self[:] = startval self._initial_size = 0 - if string is not None: - self.push(string) def is_onlyws(self): - return len(self) == 0 or str(self).isspace() + return self._initial_size==0 and (not self or str(self).isspace()) + + def part_count(self): + return super().__len__() diff --git a/Lib/email/test/test_email.py b/Lib/email/test/test_email.py --- a/Lib/email/test/test_email.py +++ b/Lib/email/test/test_email.py @@ -660,6 +660,9 @@ # Test long header wrapping class TestLongHeaders(TestEmailBase): + + maxDiff = None + def test_split_long_continuation(self): eq = self.ndiffAssertEqual msg = email.message_from_string("""\ @@ -868,14 +871,12 @@ eq = self.ndiffAssertEqual h = Header('; ' 'this_part_does_not_fit_within_maxlinelen_and_thus_should_' - 'be_on_a_line_all_by_itself;') + 'be_on_a_line_all_by_itself; ') eq(h.encode(), """\ ; - this_part_does_not_fit_within_maxlinelen_and_thus_should_be_on_a_line_all_by_itself;""") + this_part_does_not_fit_within_maxlinelen_and_thus_should_be_on_a_line_all_by_itself; """) def test_long_header_with_multiple_sequential_split_chars(self): - # Issue 11492 - eq = self.ndiffAssertEqual h = Header('This is a long line that has two whitespaces in a row. ' 'This used to cause truncation of the header when folded') @@ -883,6 +884,105 @@ This is a long line that has two whitespaces in a row. This used to cause truncation of the header when folded""") + def test_splitter_split_on_punctuation_only_if_fws(self): + eq = self.ndiffAssertEqual + h = Header('thisverylongheaderhas;semicolons;and,commas,but' + 'they;arenotlegal;fold,points') + eq(h.encode(), "thisverylongheaderhas;semicolons;and,commas,butthey;" + "arenotlegal;fold,points") + + def test_leading_splittable_in_the_middle_just_before_overlong_last_part(self): + eq = self.ndiffAssertEqual + h = Header('this is a test where we need to have more than one line ' + 'before; our final line that is just too big to fit;; ' + 'this_part_does_not_fit_within_maxlinelen_and_thus_should_' + 'be_on_a_line_all_by_itself;') + eq(h.encode(), """\ +this is a test where we need to have more than one line before; + our final line that is just too big to fit;; + this_part_does_not_fit_within_maxlinelen_and_thus_should_be_on_a_line_all_by_itself;""") + + def test_overlong_last_part_followed_by_split_point(self): + eq = self.ndiffAssertEqual + h = Header('this_part_does_not_fit_within_maxlinelen_and_thus_should_' + 'be_on_a_line_all_by_itself ') + eq(h.encode(), "this_part_does_not_fit_within_maxlinelen_and_thus_" + "should_be_on_a_line_all_by_itself ") + + def test_multiline_with_overlong_parts_separated_by_two_split_points(self): + eq = self.ndiffAssertEqual + h = Header('this_is_a__test_where_we_need_to_have_more_than_one_line_' + 'before_our_final_line_; ; ' + 'this_part_does_not_fit_within_maxlinelen_and_thus_should_' + 'be_on_a_line_all_by_itself; ') + eq(h.encode(), """\ +this_is_a__test_where_we_need_to_have_more_than_one_line_before_our_final_line_; + ; + this_part_does_not_fit_within_maxlinelen_and_thus_should_be_on_a_line_all_by_itself; """) + + def test_multiline_with_overlong_last_part_followed_by_split_point(self): + eq = self.ndiffAssertEqual + h = Header('this is a test where we need to have more than one line ' + 'before our final line; ; ' + 'this_part_does_not_fit_within_maxlinelen_and_thus_should_' + 'be_on_a_line_all_by_itself; ') + eq(h.encode(), """\ +this is a test where we need to have more than one line before our final line; + ; + this_part_does_not_fit_within_maxlinelen_and_thus_should_be_on_a_line_all_by_itself; """) + + def test_long_header_with_whitespace_runs(self): + eq = self.ndiffAssertEqual + msg = Message() + msg['From'] = 'test at dom.ain' + msg['References'] = SPACE.join([' '] * 10) + msg.set_payload('Test') + sfp = StringIO() + g = Generator(sfp) + g.flatten(msg) + eq(sfp.getvalue(), """\ +From: test at dom.ain +References: + + \x20\x20 + +Test""") + + def test_long_run_with_semi_header_splitter(self): + eq = self.ndiffAssertEqual + msg = Message() + msg['From'] = 'test at dom.ain' + msg['References'] = SPACE.join([''] * 10) + '; abc' + msg.set_payload('Test') + sfp = StringIO() + g = Generator(sfp) + g.flatten(msg) + eq(sfp.getvalue(), """\ +From: test at dom.ain +References: + + ; abc + +Test""") + + def test_splitter_split_on_punctuation_only_if_fws(self): + eq = self.ndiffAssertEqual + msg = Message() + msg['From'] = 'test at dom.ain' + msg['References'] = ('thisverylongheaderhas;semicolons;and,commas,but' + 'they;arenotlegal;fold,points') + msg.set_payload('Test') + sfp = StringIO() + g = Generator(sfp) + g.flatten(msg) + # XXX the space after the header should not be there. + eq(sfp.getvalue(), """\ +From: test at dom.ain +References:\x20 + thisverylongheaderhas;semicolons;and,commas,butthey;arenotlegal;fold,points + +Test""") + def test_no_split_long_header(self): eq = self.ndiffAssertEqual hstr = 'References: ' + 'x' * 80 @@ -973,7 +1073,7 @@ def test_long_to_header(self): eq = self.ndiffAssertEqual to = ('"Someone Test #A" ,' - ',' + ', ' '"Someone Test #B" , ' '"Someone Test #C" , ' '"Someone Test #D" ') @@ -1028,9 +1128,11 @@ msg['Received-2'] = h # This should be splitting on spaces not semicolons. self.ndiffAssertEqual(msg.as_string(maxheaderlen=78), """\ -Received-1: from FOO.TLD (vizworld.acl.foo.tld [123.452.678.9]) by hrothgar.la.mastaler.com (tmda-ofmipd) with ESMTP; +Received-1: from FOO.TLD (vizworld.acl.foo.tld [123.452.678.9]) by + hrothgar.la.mastaler.com (tmda-ofmipd) with ESMTP; Wed, 05 Mar 2003 18:10:18 -0700 -Received-2: from FOO.TLD (vizworld.acl.foo.tld [123.452.678.9]) by hrothgar.la.mastaler.com (tmda-ofmipd) with ESMTP; +Received-2: from FOO.TLD (vizworld.acl.foo.tld [123.452.678.9]) by + hrothgar.la.mastaler.com (tmda-ofmipd) with ESMTP; Wed, 05 Mar 2003 18:10:18 -0700 """) @@ -1043,12 +1145,14 @@ msg['Received-1'] = Header(h, header_name='Received-1', continuation_ws='\t') msg['Received-2'] = h - # XXX This should be splitting on spaces not commas. + # XXX The space after the ':' should not be there. self.ndiffAssertEqual(msg.as_string(maxheaderlen=78), """\ -Received-1: <15975.17901.207240.414604 at sgigritzmann1.mathematik.tu-muenchen.de> (David Bremner's message of \"Thu, - 6 Mar 2003 13:58:21 +0100\") -Received-2: <15975.17901.207240.414604 at sgigritzmann1.mathematik.tu-muenchen.de> (David Bremner's message of \"Thu, - 6 Mar 2003 13:58:21 +0100\") +Received-1:\x20 + <15975.17901.207240.414604 at sgigritzmann1.mathematik.tu-muenchen.de> (David + Bremner's message of \"Thu, 6 Mar 2003 13:58:21 +0100\") +Received-2:\x20 + <15975.17901.207240.414604 at sgigritzmann1.mathematik.tu-muenchen.de> (David + Bremner's message of \"Thu, 6 Mar 2003 13:58:21 +0100\") """) @@ -1060,8 +1164,9 @@ locQDQ4zJykFBAXJfWDjAAACYUlEQVR4nF2TQY/jIAyFc6lydlG5x8Nyp1Y69wj1PN2I5gzp""" msg['Face-1'] = t msg['Face-2'] = Header(t, header_name='Face-2') + msg['Face-3'] = ' ' + t # XXX This splitting is all wrong. It the first value line should be - # snug against the field name. + # snug against the field name or the space after the header not there. eq(msg.as_string(maxheaderlen=78), """\ Face-1:\x20 iVBORw0KGgoAAAANSUhEUgAAADAAAAAwBAMAAAClLOS0AAAAGFBMVEUAAAAkHiJeRUIcGBi9 @@ -1069,6 +1174,9 @@ Face-2:\x20 iVBORw0KGgoAAAANSUhEUgAAADAAAAAwBAMAAAClLOS0AAAAGFBMVEUAAAAkHiJeRUIcGBi9 locQDQ4zJykFBAXJfWDjAAACYUlEQVR4nF2TQY/jIAyFc6lydlG5x8Nyp1Y69wj1PN2I5gzp +Face-3:\x20 + iVBORw0KGgoAAAANSUhEUgAAADAAAAAwBAMAAAClLOS0AAAAGFBMVEUAAAAkHiJeRUIcGBi9 + locQDQ4zJykFBAXJfWDjAAACYUlEQVR4nF2TQY/jIAyFc6lydlG5x8Nyp1Y69wj1PN2I5gzp """) @@ -1080,8 +1188,8 @@ 'Wed, 16 Oct 2002 07:41:11 -0700') msg = email.message_from_string(m) eq(msg.as_string(maxheaderlen=78), '''\ -Received: from siimage.com ([172.25.1.3]) by zima.siliconimage.com with Microsoft SMTPSVC(5.0.2195.4905); - Wed, 16 Oct 2002 07:41:11 -0700 +Received: from siimage.com ([172.25.1.3]) by zima.siliconimage.com with + Microsoft SMTPSVC(5.0.2195.4905); Wed, 16 Oct 2002 07:41:11 -0700 ''') @@ -1095,9 +1203,11 @@ msg['List'] = h msg['List'] = Header(h, header_name='List') eq(msg.as_string(maxheaderlen=78), """\ -List: List-Unsubscribe: , +List: List-Unsubscribe: + , -List: List-Unsubscribe: , +List: List-Unsubscribe: + , """) @@ -4113,6 +4223,11 @@ msg = email.message_from_string("EmptyHeader:") self.assertEqual(str(msg), "EmptyHeader: \n\n") + def test_encode_preserves_leading_ws_on_value(self): + msg = Message() + msg['SomeHeader'] = ' value with leading ws' + self.assertEqual(str(msg), "SomeHeader: value with leading ws\n\n") + # Test RFC 2231 header parameters (en/de)coding diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -60,6 +60,8 @@ Library ------- +- Issue #11492: fix several issues with header folding in the email package. + - Issue #11852: Add missing imports and update tests. - Issue #11467: Fix urlparse behavior when handling urls which contains scheme -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 18 16:12:29 2011 From: python-checkins at python.org (r.david.murray) Date: Mon, 18 Apr 2011 16:12:29 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge: #11492: rewrite header folding algorithm. Less code, more passing tests. Message-ID: http://hg.python.org/cpython/rev/fcd20a565b95 changeset: 69422:fcd20a565b95 parent: 69420:d8dd02f6db1a parent: 69421:51a551acb60d user: R David Murray date: Mon Apr 18 10:11:06 2011 -0400 summary: Merge: #11492: rewrite header folding algorithm. Less code, more passing tests. files: Doc/library/email.header.rst | 14 +- Lib/email/header.py | 285 ++++++----------- Lib/test/test_email/test_email.py | 149 ++++++++- Misc/NEWS | 2 + 4 files changed, 252 insertions(+), 198 deletions(-) diff --git a/Doc/library/email.header.rst b/Doc/library/email.header.rst --- a/Doc/library/email.header.rst +++ b/Doc/library/email.header.rst @@ -109,9 +109,17 @@ Encode a message header into an RFC-compliant format, possibly wrapping long lines and encapsulating non-ASCII parts in base64 or quoted-printable - encodings. Optional *splitchars* is a string containing characters to - split long ASCII lines on, in rough support of :rfc:`2822`'s *highest - level syntactic breaks*. This doesn't affect :rfc:`2047` encoded lines. + encodings. + + Optional *splitchars* is a string containing characters which should be + given extra weight by the splitting algorithm during normal header + wrapping. This is in very rough support of :RFC:`2822`\'s 'higher level + syntactic breaks': split points preceded by a splitchar are preferred + during line splitting, with the characters preferred in the order in + which they appear in the string. Space and tab may be included in the + string to indicate whether preference should be given to one over the + other as a split point when other split chars do not appear in the line + being split. Splitchars does not affect RFC 2047 encoded lines. *maxlinelen*, if given, overrides the instance's value for the maximum line length. diff --git a/Lib/email/header.py b/Lib/email/header.py --- a/Lib/email/header.py +++ b/Lib/email/header.py @@ -26,6 +26,7 @@ SPACE8 = ' ' * 8 EMPTYSTRING = '' MAXLINELEN = 78 +FWS = ' \t' USASCII = Charset('us-ascii') UTF8 = Charset('utf-8') @@ -299,9 +300,15 @@ name was specified at Header construction time. The default value for maxlinelen is determined at header construction time. - Optional splitchars is a string containing characters to split long - ASCII lines on, in rough support of RFC 2822's `highest level - syntactic breaks'. This doesn't affect RFC 2047 encoded lines. + Optional splitchars is a string containing characters which should be + given extra weight by the splitting algorithm during normal header + wrapping. This is in very rough support of RFC 2822's `higher level + syntactic breaks': split points preceded by a splitchar are preferred + during line splitting, with the characters preferred in the order in + which they appear in the string. Space and tab may be included in the + string to indicate whether preference should be given to one over the + other as a split point when other split chars do not appear in the line + being split. Splitchars does not affect RFC 2047 encoded lines. Optional linesep is a string to be used to separate the lines of the value. The default value is the most useful for typical @@ -320,13 +327,19 @@ self._continuation_ws, splitchars) for string, charset in self._chunks: lines = string.splitlines() - formatter.feed(lines[0] if lines else '', charset) + if lines: + formatter.feed('', lines[0], charset) + else: + formatter.feed('', '', charset) for line in lines[1:]: formatter.newline() if charset.header_encoding is not None: - formatter.feed(self._continuation_ws, USASCII) - line = ' ' + line.lstrip() - formatter.feed(line, charset) + formatter.feed(self._continuation_ws, ' ' + line.lstrip(), + charset) + else: + sline = line.lstrip() + fws = line[:len(line)-len(sline)] + formatter.feed(fws, sline, charset) if len(lines) > 1: formatter.newline() formatter.add_transition() @@ -360,7 +373,7 @@ def __init__(self, headerlen, maxlen, continuation_ws, splitchars): self._maxlen = maxlen self._continuation_ws = continuation_ws - self._continuation_ws_len = len(continuation_ws.replace('\t', SPACE8)) + self._continuation_ws_len = len(continuation_ws) self._splitchars = splitchars self._lines = [] self._current_line = _Accumulator(headerlen) @@ -374,43 +387,26 @@ def newline(self): end_of_line = self._current_line.pop() - if end_of_line is not None: - self._current_line.push(end_of_line) + if end_of_line != (' ', ''): + self._current_line.push(*end_of_line) if len(self._current_line) > 0: - self._lines.append(str(self._current_line)) + if self._current_line.is_onlyws(): + self._lines[-1] += str(self._current_line) + else: + self._lines.append(str(self._current_line)) self._current_line.reset() def add_transition(self): - self._current_line.push(None) + self._current_line.push(' ', '') - def feed(self, string, charset): - # If the string itself fits on the current line in its encoded format, - # then add it now and be done with it. - encoded_string = charset.header_encode(string) - if len(encoded_string) + len(self._current_line) <= self._maxlen: - self._current_line.push(encoded_string) - return + def feed(self, fws, string, charset): # If the charset has no header encoding (i.e. it is an ASCII encoding) # then we must split the header at the "highest level syntactic break" # possible. Note that we don't have a lot of smarts about field # syntax; we just try to break on semi-colons, then commas, then # whitespace. Eventually, this should be pluggable. if charset.header_encoding is None: - for ch in self._splitchars: - if ch in string: - break - else: - ch = None - # If there's no available split character then regardless of - # whether the string fits on the line, we have to put it on a line - # by itself. - if ch is None: - if not self._current_line.is_onlyws(): - self._lines.append(str(self._current_line)) - self._current_line.reset(self._continuation_ws) - self._current_line.push(encoded_string) - else: - self._ascii_split(string, ch) + self._ascii_split(fws, string, self._splitchars) return # Otherwise, we're doing either a Base64 or a quoted-printable # encoding which means we don't need to split the line on syntactic @@ -428,15 +424,14 @@ # There are no encoded lines, so we're done. return if first_line is not None: - self._current_line.push(first_line) - self._lines.append(str(self._current_line)) - self._current_line.reset(self._continuation_ws) + self._append_chunk(fws, first_line) try: last_line = encoded_lines.pop() except IndexError: # There was only one line. return - self._current_line.push(last_line) + self.newline() + self._current_line.push(self._continuation_ws, last_line) # Everything else are full lines in themselves. for line in encoded_lines: self._lines.append(self._continuation_ws + line) @@ -447,162 +442,96 @@ while True: yield self._maxlen - self._continuation_ws_len - def _ascii_split(self, string, ch): - holding = _Accumulator() - # Split the line on the split character, preserving it. If the split - # character is whitespace RFC 2822 $2.2.3 requires us to fold on the - # whitespace, so that the line leads with the original whitespace we - # split on. However, if a higher syntactic break is used instead - # (e.g. comma or semicolon), the folding should happen after the split - # character. But then in that case, we need to add our own - # continuation whitespace -- although won't that break unfolding? - for part, splitpart, nextpart in _spliterator(ch, string): - if not splitpart: - # No splitpart means this is the last chunk. Put this part - # either on the current line or the next line depending on - # whether it fits. - holding.push(part) - if len(holding) + len(self._current_line) <= self._maxlen: - # It fits, but we're done. - self._current_line.push(str(holding)) + def _ascii_split(self, fws, string, splitchars): + # The RFC 2822 header folding algorithm is simple in principle but + # complex in practice. Lines may be folded any place where "folding + # white space" appears by inserting a linesep character in front of the + # FWS. The complication is that not all spaces or tabs qualify as FWS, + # and we are also supposed to prefer to break at "higher level + # syntactic breaks". We can't do either of these without intimate + # knowledge of the structure of structured headers, which we don't have + # here. So the best we can do here is prefer to break at the specified + # splitchars, and hope that we don't choose any spaces or tabs that + # aren't legal FWS. (This is at least better than the old algorithm, + # where we would sometimes *introduce* FWS after a splitchar, or the + # algorithm before that, where we would turn all white space runs into + # single spaces or tabs.) + parts = re.split("(["+FWS+"]+)", fws+string) + if parts[0]: + parts[:0] = [''] + else: + parts.pop(0) + for fws, part in zip(*[iter(parts)]*2): + self._append_chunk(fws, part) + + def _append_chunk(self, fws, string): + self._current_line.push(fws, string) + if len(self._current_line) > self._maxlen: + # Find the best split point, working backward from the end. + # There might be none, on a long first line. + for ch in self._splitchars: + for i in range(self._current_line.part_count()-1, 0, -1): + if ch.isspace(): + fws = self._current_line[i][0] + if fws and fws[0]==ch: + break + prevpart = self._current_line[i-1][1] + if prevpart and prevpart[-1]==ch: + break else: - # It doesn't fit, but we're done. Before pushing a new - # line, watch out for the current line containing only - # whitespace. - holding.pop() - if self._current_line.is_onlyws() and holding.is_onlyws(): - # Don't start a new line. - holding.push(part) - part = None - self._current_line.push(str(holding)) - self._lines.append(str(self._current_line)) - if part is None: - self._current_line.reset() - else: - holding.reset(part) - self._current_line.reset(str(holding)) + continue + break + else: + fws, part = self._current_line.pop() + if self._current_line._initial_size > 0: + # There will be a header, so leave it on a line by itself. + self.newline() + if not fws: + # We don't use continuation_ws here because the whitespace + # after a header should always be a space. + fws = ' ' + self._current_line.push(fws, part) return - elif not nextpart: - # There must be some trailing or duplicated split characters - # because we - # found a split character but no next part. In this case we - # must treat the thing to fit as the part + splitpart because - # if splitpart is whitespace it's not allowed to be the only - # thing on the line, and if it's not whitespace we must split - # after the syntactic break. - holding_prelen = len(holding) - holding.push(part + splitpart) - if len(holding) + len(self._current_line) <= self._maxlen: - self._current_line.push(str(holding)) - elif holding_prelen == 0: - # This is the only chunk left so it has to go on the - # current line. - self._current_line.push(str(holding)) - else: - save_part = holding.pop() - self._current_line.push(str(holding)) - self._lines.append(str(self._current_line)) - holding.reset(save_part) - self._current_line.reset(str(holding)) - holding.reset() - elif not part: - # We're leading with a split character. See if the splitpart - # and nextpart fits on the current line. - holding.push(splitpart + nextpart) - holding_len = len(holding) - # We know we're not leaving the nextpart on the stack. - holding.pop() - if holding_len + len(self._current_line) <= self._maxlen: - holding.push(splitpart) - else: - # It doesn't fit. Since there's no current part really - # the best we can do is start a new line and push the - # split part onto it. - self._current_line.push(str(holding)) - holding.reset() - if len(self._current_line) > 0 and self._lines: - self._lines.append(str(self._current_line)) - self._current_line.reset() - holding.push(splitpart) - else: - # All three parts are present. First let's see if all three - # parts will fit on the current line. If so, we don't need to - # split it. - holding.push(part + splitpart + nextpart) - holding_len = len(holding) - # Pop the part because we'll push nextpart on the next - # iteration through the loop. - holding.pop() - if holding_len + len(self._current_line) <= self._maxlen: - holding.push(part + splitpart) - else: - # The entire thing doesn't fit. See if we need to split - # before or after the split characters. - if splitpart.isspace(): - # Split before whitespace. Remember that the - # whitespace becomes the continuation whitespace of - # the next line so it goes to current_line not holding. - holding.push(part) - self._current_line.push(str(holding)) - holding.reset() - self._lines.append(str(self._current_line)) - self._current_line.reset(splitpart) - else: - # Split after non-whitespace. The continuation - # whitespace comes from the instance variable. - holding.push(part + splitpart) - self._current_line.push(str(holding)) - holding.reset() - self._lines.append(str(self._current_line)) - if nextpart[0].isspace(): - self._current_line.reset() - else: - self._current_line.reset(self._continuation_ws) - # Get the last of the holding part - self._current_line.push(str(holding)) + remainder = self._current_line.pop_from(i) + self._lines.append(str(self._current_line)) + self._current_line.reset(remainder) - -def _spliterator(character, string): - parts = list(reversed(re.split('(%s)' % character, string))) - while parts: - part = parts.pop() - splitparts = (parts.pop() if parts else None) - nextpart = (parts.pop() if parts else None) - yield (part, splitparts, nextpart) - if nextpart is not None: - parts.append(nextpart) +class _Accumulator(list): - -class _Accumulator: def __init__(self, initial_size=0): self._initial_size = initial_size - self._current = [] + super().__init__() - def push(self, string): - self._current.append(string) + def push(self, fws, string): + self.append((fws, string)) + + def pop_from(self, i=0): + popped = self[i:] + self[i:] = [] + return popped def pop(self): - if not self._current: - return None - return self._current.pop() + if self.part_count()==0: + return ('', '') + return super().pop() def __len__(self): - return sum(((1 if string is None else len(string)) - for string in self._current), + return sum((len(fws)+len(part) for fws, part in self), self._initial_size) def __str__(self): - if self._current and self._current[-1] is None: - self._current.pop() - return EMPTYSTRING.join((' ' if string is None else string) - for string in self._current) + return EMPTYSTRING.join((EMPTYSTRING.join((fws, part)) + for fws, part in self)) - def reset(self, string=None): - self._current = [] + def reset(self, startval=None): + if startval is None: + startval = [] + self[:] = startval self._initial_size = 0 - if string is not None: - self.push(string) def is_onlyws(self): - return len(self) == 0 or str(self).isspace() + return self._initial_size==0 and (not self or str(self).isspace()) + + def part_count(self): + return super().__len__() diff --git a/Lib/test/test_email/test_email.py b/Lib/test/test_email/test_email.py --- a/Lib/test/test_email/test_email.py +++ b/Lib/test/test_email/test_email.py @@ -645,6 +645,9 @@ # Test long header wrapping class TestLongHeaders(TestEmailBase): + + maxDiff = None + def test_split_long_continuation(self): eq = self.ndiffAssertEqual msg = email.message_from_string("""\ @@ -853,14 +856,12 @@ eq = self.ndiffAssertEqual h = Header('; ' 'this_part_does_not_fit_within_maxlinelen_and_thus_should_' - 'be_on_a_line_all_by_itself;') + 'be_on_a_line_all_by_itself; ') eq(h.encode(), """\ ; - this_part_does_not_fit_within_maxlinelen_and_thus_should_be_on_a_line_all_by_itself;""") + this_part_does_not_fit_within_maxlinelen_and_thus_should_be_on_a_line_all_by_itself; """) def test_long_header_with_multiple_sequential_split_chars(self): - # Issue 11492 - eq = self.ndiffAssertEqual h = Header('This is a long line that has two whitespaces in a row. ' 'This used to cause truncation of the header when folded') @@ -868,6 +869,105 @@ This is a long line that has two whitespaces in a row. This used to cause truncation of the header when folded""") + def test_splitter_split_on_punctuation_only_if_fws(self): + eq = self.ndiffAssertEqual + h = Header('thisverylongheaderhas;semicolons;and,commas,but' + 'they;arenotlegal;fold,points') + eq(h.encode(), "thisverylongheaderhas;semicolons;and,commas,butthey;" + "arenotlegal;fold,points") + + def test_leading_splittable_in_the_middle_just_before_overlong_last_part(self): + eq = self.ndiffAssertEqual + h = Header('this is a test where we need to have more than one line ' + 'before; our final line that is just too big to fit;; ' + 'this_part_does_not_fit_within_maxlinelen_and_thus_should_' + 'be_on_a_line_all_by_itself;') + eq(h.encode(), """\ +this is a test where we need to have more than one line before; + our final line that is just too big to fit;; + this_part_does_not_fit_within_maxlinelen_and_thus_should_be_on_a_line_all_by_itself;""") + + def test_overlong_last_part_followed_by_split_point(self): + eq = self.ndiffAssertEqual + h = Header('this_part_does_not_fit_within_maxlinelen_and_thus_should_' + 'be_on_a_line_all_by_itself ') + eq(h.encode(), "this_part_does_not_fit_within_maxlinelen_and_thus_" + "should_be_on_a_line_all_by_itself ") + + def test_multiline_with_overlong_parts_separated_by_two_split_points(self): + eq = self.ndiffAssertEqual + h = Header('this_is_a__test_where_we_need_to_have_more_than_one_line_' + 'before_our_final_line_; ; ' + 'this_part_does_not_fit_within_maxlinelen_and_thus_should_' + 'be_on_a_line_all_by_itself; ') + eq(h.encode(), """\ +this_is_a__test_where_we_need_to_have_more_than_one_line_before_our_final_line_; + ; + this_part_does_not_fit_within_maxlinelen_and_thus_should_be_on_a_line_all_by_itself; """) + + def test_multiline_with_overlong_last_part_followed_by_split_point(self): + eq = self.ndiffAssertEqual + h = Header('this is a test where we need to have more than one line ' + 'before our final line; ; ' + 'this_part_does_not_fit_within_maxlinelen_and_thus_should_' + 'be_on_a_line_all_by_itself; ') + eq(h.encode(), """\ +this is a test where we need to have more than one line before our final line; + ; + this_part_does_not_fit_within_maxlinelen_and_thus_should_be_on_a_line_all_by_itself; """) + + def test_long_header_with_whitespace_runs(self): + eq = self.ndiffAssertEqual + msg = Message() + msg['From'] = 'test at dom.ain' + msg['References'] = SPACE.join([' '] * 10) + msg.set_payload('Test') + sfp = StringIO() + g = Generator(sfp) + g.flatten(msg) + eq(sfp.getvalue(), """\ +From: test at dom.ain +References: + + \x20\x20 + +Test""") + + def test_long_run_with_semi_header_splitter(self): + eq = self.ndiffAssertEqual + msg = Message() + msg['From'] = 'test at dom.ain' + msg['References'] = SPACE.join([''] * 10) + '; abc' + msg.set_payload('Test') + sfp = StringIO() + g = Generator(sfp) + g.flatten(msg) + eq(sfp.getvalue(), """\ +From: test at dom.ain +References: + + ; abc + +Test""") + + def test_splitter_split_on_punctuation_only_if_fws(self): + eq = self.ndiffAssertEqual + msg = Message() + msg['From'] = 'test at dom.ain' + msg['References'] = ('thisverylongheaderhas;semicolons;and,commas,but' + 'they;arenotlegal;fold,points') + msg.set_payload('Test') + sfp = StringIO() + g = Generator(sfp) + g.flatten(msg) + # XXX the space after the header should not be there. + eq(sfp.getvalue(), """\ +From: test at dom.ain +References:\x20 + thisverylongheaderhas;semicolons;and,commas,butthey;arenotlegal;fold,points + +Test""") + def test_no_split_long_header(self): eq = self.ndiffAssertEqual hstr = 'References: ' + 'x' * 80 @@ -958,7 +1058,7 @@ def test_long_to_header(self): eq = self.ndiffAssertEqual to = ('"Someone Test #A" ,' - ',' + ', ' '"Someone Test #B" , ' '"Someone Test #C" , ' '"Someone Test #D" ') @@ -1013,9 +1113,11 @@ msg['Received-2'] = h # This should be splitting on spaces not semicolons. self.ndiffAssertEqual(msg.as_string(maxheaderlen=78), """\ -Received-1: from FOO.TLD (vizworld.acl.foo.tld [123.452.678.9]) by hrothgar.la.mastaler.com (tmda-ofmipd) with ESMTP; +Received-1: from FOO.TLD (vizworld.acl.foo.tld [123.452.678.9]) by + hrothgar.la.mastaler.com (tmda-ofmipd) with ESMTP; Wed, 05 Mar 2003 18:10:18 -0700 -Received-2: from FOO.TLD (vizworld.acl.foo.tld [123.452.678.9]) by hrothgar.la.mastaler.com (tmda-ofmipd) with ESMTP; +Received-2: from FOO.TLD (vizworld.acl.foo.tld [123.452.678.9]) by + hrothgar.la.mastaler.com (tmda-ofmipd) with ESMTP; Wed, 05 Mar 2003 18:10:18 -0700 """) @@ -1028,12 +1130,14 @@ msg['Received-1'] = Header(h, header_name='Received-1', continuation_ws='\t') msg['Received-2'] = h - # XXX This should be splitting on spaces not commas. + # XXX The space after the ':' should not be there. self.ndiffAssertEqual(msg.as_string(maxheaderlen=78), """\ -Received-1: <15975.17901.207240.414604 at sgigritzmann1.mathematik.tu-muenchen.de> (David Bremner's message of \"Thu, - 6 Mar 2003 13:58:21 +0100\") -Received-2: <15975.17901.207240.414604 at sgigritzmann1.mathematik.tu-muenchen.de> (David Bremner's message of \"Thu, - 6 Mar 2003 13:58:21 +0100\") +Received-1:\x20 + <15975.17901.207240.414604 at sgigritzmann1.mathematik.tu-muenchen.de> (David + Bremner's message of \"Thu, 6 Mar 2003 13:58:21 +0100\") +Received-2:\x20 + <15975.17901.207240.414604 at sgigritzmann1.mathematik.tu-muenchen.de> (David + Bremner's message of \"Thu, 6 Mar 2003 13:58:21 +0100\") """) @@ -1045,8 +1149,9 @@ locQDQ4zJykFBAXJfWDjAAACYUlEQVR4nF2TQY/jIAyFc6lydlG5x8Nyp1Y69wj1PN2I5gzp""" msg['Face-1'] = t msg['Face-2'] = Header(t, header_name='Face-2') + msg['Face-3'] = ' ' + t # XXX This splitting is all wrong. It the first value line should be - # snug against the field name. + # snug against the field name or the space after the header not there. eq(msg.as_string(maxheaderlen=78), """\ Face-1:\x20 iVBORw0KGgoAAAANSUhEUgAAADAAAAAwBAMAAAClLOS0AAAAGFBMVEUAAAAkHiJeRUIcGBi9 @@ -1054,6 +1159,9 @@ Face-2:\x20 iVBORw0KGgoAAAANSUhEUgAAADAAAAAwBAMAAAClLOS0AAAAGFBMVEUAAAAkHiJeRUIcGBi9 locQDQ4zJykFBAXJfWDjAAACYUlEQVR4nF2TQY/jIAyFc6lydlG5x8Nyp1Y69wj1PN2I5gzp +Face-3:\x20 + iVBORw0KGgoAAAANSUhEUgAAADAAAAAwBAMAAAClLOS0AAAAGFBMVEUAAAAkHiJeRUIcGBi9 + locQDQ4zJykFBAXJfWDjAAACYUlEQVR4nF2TQY/jIAyFc6lydlG5x8Nyp1Y69wj1PN2I5gzp """) @@ -1065,8 +1173,8 @@ 'Wed, 16 Oct 2002 07:41:11 -0700') msg = email.message_from_string(m) eq(msg.as_string(maxheaderlen=78), '''\ -Received: from siimage.com ([172.25.1.3]) by zima.siliconimage.com with Microsoft SMTPSVC(5.0.2195.4905); - Wed, 16 Oct 2002 07:41:11 -0700 +Received: from siimage.com ([172.25.1.3]) by zima.siliconimage.com with + Microsoft SMTPSVC(5.0.2195.4905); Wed, 16 Oct 2002 07:41:11 -0700 ''') @@ -1080,9 +1188,11 @@ msg['List'] = h msg['List'] = Header(h, header_name='List') eq(msg.as_string(maxheaderlen=78), """\ -List: List-Unsubscribe: , +List: List-Unsubscribe: + , -List: List-Unsubscribe: , +List: List-Unsubscribe: + , """) @@ -4147,6 +4257,11 @@ msg = email.message_from_string("EmptyHeader:") self.assertEqual(str(msg), "EmptyHeader: \n\n") + def test_encode_preserves_leading_ws_on_value(self): + msg = Message() + msg['SomeHeader'] = ' value with leading ws' + self.assertEqual(str(msg), "SomeHeader: value with leading ws\n\n") + # Test RFC 2231 header parameters (en/de)coding diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -110,6 +110,8 @@ Library ------- +- Issue #11492: fix several issues with header folding in the email package. + - Issue #11852: Add missing imports and update tests. - Issue #11467: Fix urlparse behavior when handling urls which contains scheme -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 18 16:30:25 2011 From: python-checkins at python.org (victor.stinner) Date: Mon, 18 Apr 2011 16:30:25 +0200 Subject: [Python-checkins] cpython (3.1): Issue #11768: The signal handler of the signal module only calls Message-ID: http://hg.python.org/cpython/rev/319f7af9ee5e changeset: 69423:319f7af9ee5e branch: 3.1 parent: 69418:6e090d78857c user: Victor Stinner date: Mon Apr 18 16:25:56 2011 +0200 summary: Issue #11768: The signal handler of the signal module only calls Py_AddPendingCall() for the first signal to fix a deadlock on reentrant or parallel calls. PyErr_SetInterrupt() writes also into the wake up file. files: Misc/NEWS | 4 ++++ Modules/signalmodule.c | 26 ++++++++++++++++---------- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -55,6 +55,10 @@ Library ------- +- Issue #11768: The signal handler of the signal module only calls + Py_AddPendingCall() for the first signal to fix a deadlock on reentrant or + parallel calls. PyErr_SetInterrupt() writes also into the wake up file. + - Issue #11467: Fix urlparse behavior when handling urls which contains scheme specific part only digits. Patch by Santoso Wijaya. diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c --- a/Modules/signalmodule.c +++ b/Modules/signalmodule.c @@ -164,6 +164,20 @@ } static void +trip_signal(int sig_num) +{ + Handlers[sig_num].tripped = 1; + if (is_tripped) + return; + /* Set is_tripped after setting .tripped, as it gets + cleared in PyErr_CheckSignals() before .tripped. */ + is_tripped = 1; + Py_AddPendingCall(checksignals_witharg, NULL); + if (wakeup_fd != -1) + write(wakeup_fd, "\0", 1); +} + +static void signal_handler(int sig_num) { int save_errno = errno; @@ -180,13 +194,7 @@ if (getpid() == main_pid) #endif { - Handlers[sig_num].tripped = 1; - /* Set is_tripped after setting .tripped, as it gets - cleared in PyErr_CheckSignals() before .tripped. */ - is_tripped = 1; - Py_AddPendingCall(checksignals_witharg, NULL); - if (wakeup_fd != -1) - write(wakeup_fd, "\0", 1); + trip_signal(sig_num); } #ifndef HAVE_SIGACTION @@ -932,9 +940,7 @@ void PyErr_SetInterrupt(void) { - is_tripped = 1; - Handlers[SIGINT].tripped = 1; - Py_AddPendingCall((int (*)(void *))PyErr_CheckSignals, NULL); + trip_signal(SIGINT); } void -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 18 16:30:26 2011 From: python-checkins at python.org (victor.stinner) Date: Mon, 18 Apr 2011 16:30:26 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): (Merge 3.1) Issue #11768: The signal handler of the signal module only calls Message-ID: http://hg.python.org/cpython/rev/28ab8c6ad8f9 changeset: 69424:28ab8c6ad8f9 branch: 3.2 parent: 69421:51a551acb60d parent: 69423:319f7af9ee5e user: Victor Stinner date: Mon Apr 18 16:28:39 2011 +0200 summary: (Merge 3.1) Issue #11768: The signal handler of the signal module only calls Py_AddPendingCall() for the first signal to fix a deadlock on reentrant or parallel calls. PyErr_SetInterrupt() writes also into the wake up file. files: Misc/NEWS | 4 ++++ Modules/signalmodule.c | 26 ++++++++++++++++---------- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -60,6 +60,10 @@ Library ------- +- Issue #11768: The signal handler of the signal module only calls + Py_AddPendingCall() for the first signal to fix a deadlock on reentrant or + parallel calls. PyErr_SetInterrupt() writes also into the wake up file. + - Issue #11492: fix several issues with header folding in the email package. - Issue #11852: Add missing imports and update tests. diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c --- a/Modules/signalmodule.c +++ b/Modules/signalmodule.c @@ -166,6 +166,20 @@ } static void +trip_signal(int sig_num) +{ + Handlers[sig_num].tripped = 1; + if (is_tripped) + return; + /* Set is_tripped after setting .tripped, as it gets + cleared in PyErr_CheckSignals() before .tripped. */ + is_tripped = 1; + Py_AddPendingCall(checksignals_witharg, NULL); + if (wakeup_fd != -1) + write(wakeup_fd, "\0", 1); +} + +static void signal_handler(int sig_num) { int save_errno = errno; @@ -182,13 +196,7 @@ if (getpid() == main_pid) #endif { - Handlers[sig_num].tripped = 1; - /* Set is_tripped after setting .tripped, as it gets - cleared in PyErr_CheckSignals() before .tripped. */ - is_tripped = 1; - Py_AddPendingCall(checksignals_witharg, NULL); - if (wakeup_fd != -1) - write(wakeup_fd, "\0", 1); + trip_signal(sig_num); } #ifndef HAVE_SIGACTION @@ -946,9 +954,7 @@ void PyErr_SetInterrupt(void) { - is_tripped = 1; - Handlers[SIGINT].tripped = 1; - Py_AddPendingCall((int (*)(void *))PyErr_CheckSignals, NULL); + trip_signal(SIGINT); } void -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 18 16:30:30 2011 From: python-checkins at python.org (victor.stinner) Date: Mon, 18 Apr 2011 16:30:30 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): (Merge 3.2) Issue #11768: The signal handler of the signal module only calls Message-ID: http://hg.python.org/cpython/rev/fdcbc8453304 changeset: 69425:fdcbc8453304 parent: 69422:fcd20a565b95 parent: 69424:28ab8c6ad8f9 user: Victor Stinner date: Mon Apr 18 16:30:17 2011 +0200 summary: (Merge 3.2) Issue #11768: The signal handler of the signal module only calls Py_AddPendingCall() for the first signal to fix a deadlock on reentrant or parallel calls. PyErr_SetInterrupt() writes also into the wake up file. files: Lib/test/test_threadsignals.py | 8 ------ Misc/NEWS | 4 +++ Modules/signalmodule.c | 26 +++++++++++++-------- 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/Lib/test/test_threadsignals.py b/Lib/test/test_threadsignals.py --- a/Lib/test/test_threadsignals.py +++ b/Lib/test/test_threadsignals.py @@ -30,14 +30,9 @@ # a function that will be spawned as a separate thread. def send_signals(): - print("send_signals: enter (thread %s)" % thread.get_ident(), file=sys.stderr) - print("send_signals: raise SIGUSR1", file=sys.stderr) os.kill(process_pid, signal.SIGUSR1) - print("send_signals: raise SIGUSR2", file=sys.stderr) os.kill(process_pid, signal.SIGUSR2) - print("send_signals: release signalled_all", file=sys.stderr) signalled_all.release() - print("send_signals: exit (thread %s)" % thread.get_ident(), file=sys.stderr) class ThreadSignals(unittest.TestCase): @@ -46,12 +41,9 @@ # We spawn a thread, have the thread send two signals, and # wait for it to finish. Check that we got both signals # and that they were run by the main thread. - print("test_signals: acquire lock (thread %s)" % thread.get_ident(), file=sys.stderr) signalled_all.acquire() self.spawnSignallingThread() - print("test_signals: wait lock (thread %s)" % thread.get_ident(), file=sys.stderr) signalled_all.acquire() - print("test_signals: lock acquired", file=sys.stderr) # the signals that we asked the kernel to send # will come back, but we don't know when. # (it might even be after the thread exits diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -110,6 +110,10 @@ Library ------- +- Issue #11768: The signal handler of the signal module only calls + Py_AddPendingCall() for the first signal to fix a deadlock on reentrant or + parallel calls. PyErr_SetInterrupt() writes also into the wake up file. + - Issue #11492: fix several issues with header folding in the email package. - Issue #11852: Add missing imports and update tests. diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c --- a/Modules/signalmodule.c +++ b/Modules/signalmodule.c @@ -166,6 +166,20 @@ } static void +trip_signal(int sig_num) +{ + Handlers[sig_num].tripped = 1; + if (is_tripped) + return; + /* Set is_tripped after setting .tripped, as it gets + cleared in PyErr_CheckSignals() before .tripped. */ + is_tripped = 1; + Py_AddPendingCall(checksignals_witharg, NULL); + if (wakeup_fd != -1) + write(wakeup_fd, "\0", 1); +} + +static void signal_handler(int sig_num) { int save_errno = errno; @@ -182,13 +196,7 @@ if (getpid() == main_pid) #endif { - Handlers[sig_num].tripped = 1; - /* Set is_tripped after setting .tripped, as it gets - cleared in PyErr_CheckSignals() before .tripped. */ - is_tripped = 1; - Py_AddPendingCall(checksignals_witharg, NULL); - if (wakeup_fd != -1) - write(wakeup_fd, "\0", 1); + trip_signal(sig_num); } #ifndef HAVE_SIGACTION @@ -946,9 +954,7 @@ void PyErr_SetInterrupt(void) { - is_tripped = 1; - Handlers[SIGINT].tripped = 1; - Py_AddPendingCall((int (*)(void *))PyErr_CheckSignals, NULL); + trip_signal(SIGINT); } void -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 18 16:34:33 2011 From: python-checkins at python.org (victor.stinner) Date: Mon, 18 Apr 2011 16:34:33 +0200 Subject: [Python-checkins] cpython (2.7): (Merge 3.1) Issue #11768: The signal handler of the signal module only calls Message-ID: http://hg.python.org/cpython/rev/7d355c2ff3d4 changeset: 69426:7d355c2ff3d4 branch: 2.7 parent: 69417:fc2def15ab11 user: Victor Stinner date: Mon Apr 18 16:33:28 2011 +0200 summary: (Merge 3.1) Issue #11768: The signal handler of the signal module only calls Py_AddPendingCall() for the first signal to fix a deadlock on reentrant or parallel calls. PyErr_SetInterrupt() writes also into the wake up file. files: Misc/NEWS | 4 ++++ Modules/signalmodule.c | 26 ++++++++++++++++---------- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -55,6 +55,10 @@ Library ------- +- Issue #11768: The signal handler of the signal module only calls + Py_AddPendingCall() for the first signal to fix a deadlock on reentrant or + parallel calls. PyErr_SetInterrupt() writes also into the wake up file. + - Issue #11442: Add a charset parameter to the Content-type in SimpleHTTPServer to avoid XSS attacks. diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c --- a/Modules/signalmodule.c +++ b/Modules/signalmodule.c @@ -167,6 +167,20 @@ } static void +trip_signal(int sig_num) +{ + Handlers[sig_num].tripped = 1; + if (is_tripped) + return; + /* Set is_tripped after setting .tripped, as it gets + cleared in PyErr_CheckSignals() before .tripped. */ + is_tripped = 1; + Py_AddPendingCall(checksignals_witharg, NULL); + if (wakeup_fd != -1) + write(wakeup_fd, "\0", 1); +} + +static void signal_handler(int sig_num) { int save_errno = errno; @@ -183,13 +197,7 @@ if (getpid() == main_pid) #endif { - Handlers[sig_num].tripped = 1; - /* Set is_tripped after setting .tripped, as it gets - cleared in PyErr_CheckSignals() before .tripped. */ - is_tripped = 1; - Py_AddPendingCall(checksignals_witharg, NULL); - if (wakeup_fd != -1) - write(wakeup_fd, "\0", 1); + trip_signal(sig_num); } #ifndef HAVE_SIGACTION @@ -934,9 +942,7 @@ void PyErr_SetInterrupt(void) { - is_tripped = 1; - Handlers[SIGINT].tripped = 1; - Py_AddPendingCall((int (*)(void *))PyErr_CheckSignals, NULL); + trip_signal(SIGINT); } void -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 18 16:34:35 2011 From: python-checkins at python.org (victor.stinner) Date: Mon, 18 Apr 2011 16:34:35 +0200 Subject: [Python-checkins] cpython (2.7): Issue #11768: signal.set_wakeup_fd() and PySignal_SetWakeupFd() added in 2.6 Message-ID: http://hg.python.org/cpython/rev/ebd080593351 changeset: 69427:ebd080593351 branch: 2.7 user: Victor Stinner date: Mon Apr 18 16:34:31 2011 +0200 summary: Issue #11768: signal.set_wakeup_fd() and PySignal_SetWakeupFd() added in 2.6 Fix the documentation. files: Doc/c-api/exceptions.rst | 2 ++ Doc/library/signal.rst | 2 ++ 2 files changed, 4 insertions(+), 0 deletions(-) diff --git a/Doc/c-api/exceptions.rst b/Doc/c-api/exceptions.rst --- a/Doc/c-api/exceptions.rst +++ b/Doc/c-api/exceptions.rst @@ -347,6 +347,8 @@ error checking. *fd* should be a valid file descriptor. The function should only be called from the main thread. + .. versionadded:: 2.6 + .. cfunction:: PyObject* PyErr_NewException(char *name, PyObject *base, PyObject *dict) diff --git a/Doc/library/signal.rst b/Doc/library/signal.rst --- a/Doc/library/signal.rst +++ b/Doc/library/signal.rst @@ -204,6 +204,8 @@ attempting to call it from other threads will cause a :exc:`ValueError` exception to be raised. + .. versionadded:: 2.6 + .. function:: siginterrupt(signalnum, flag) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 18 20:00:38 2011 From: python-checkins at python.org (r.david.murray) Date: Mon, 18 Apr 2011 20:00:38 +0200 Subject: [Python-checkins] cpython: #11731: simplify/enhance parser/generator API by introducing policy objects. Message-ID: http://hg.python.org/cpython/rev/2f3fda9d3906 changeset: 69428:2f3fda9d3906 parent: 69425:fdcbc8453304 user: R David Murray date: Mon Apr 18 13:59:37 2011 -0400 summary: #11731: simplify/enhance parser/generator API by introducing policy objects. This new interface will also allow for future planned enhancements in control over the parser/generator without requiring any additional complexity in the parser/generator API. Patch reviewed by ?ric Araujo and Barry Warsaw. files: Doc/library/email.generator.rst | 55 ++- Doc/library/email.parser.rst | 54 +++- Doc/library/email.policy.rst | 179 ++++++++++++++ Lib/email/errors.py | 2 +- Lib/email/feedparser.py | 23 +- Lib/email/generator.py | 62 ++- Lib/email/parser.py | 11 +- Lib/email/policy.py | 174 +++++++++++++ Lib/test/test_email/__init__.py | 2 + Lib/test/test_email/test_email.py | 146 ++++++++++- Lib/test/test_email/test_generator.py | 136 ++++++++++ Lib/test/test_email/test_policy.py | 148 +++++++++++ Misc/NEWS | 3 + 13 files changed, 913 insertions(+), 82 deletions(-) diff --git a/Doc/library/email.generator.rst b/Doc/library/email.generator.rst --- a/Doc/library/email.generator.rst +++ b/Doc/library/email.generator.rst @@ -32,7 +32,8 @@ :mod:`email.generator` module: -.. class:: Generator(outfp, mangle_from_=True, maxheaderlen=78) +.. class:: Generator(outfp, mangle_from_=True, maxheaderlen=78, *, \ + policy=policy.default) The constructor for the :class:`Generator` class takes a :term:`file-like object` called *outfp* for an argument. *outfp* must support the :meth:`write` method @@ -53,10 +54,16 @@ :class:`~email.header.Header` class. Set to zero to disable header wrapping. The default is 78, as recommended (but not required) by :rfc:`2822`. + The *policy* keyword specifies a :mod:`~email.policy` object that controls a + number of aspects of the generator's operation. The default policy + maintains backward compatibility. + + .. versionchanged:: 3.3 Added the *policy* keyword. + The other public :class:`Generator` methods are: - .. method:: flatten(msg, unixfrom=False, linesep='\\n') + .. method:: flatten(msg, unixfrom=False, linesep=None) Print the textual representation of the message object structure rooted at *msg* to the output file specified when the :class:`Generator` instance @@ -72,12 +79,13 @@ Note that for subparts, no envelope header is ever printed. Optional *linesep* specifies the line separator character used to - terminate lines in the output. It defaults to ``\n`` because that is - the most useful value for Python application code (other library packages - expect ``\n`` separated lines). ``linesep=\r\n`` can be used to - generate output with RFC-compliant line separators. + terminate lines in the output. If specified it overrides the value + specified by the ``Generator``\'s ``policy``. - Messages parsed with a Bytes parser that have a + Because strings cannot represent non-ASCII bytes, ``Generator`` ignores + the value of the :attr:`~email.policy.Policy.must_be_7bit` + :mod:`~email.policy` setting and operates as if it were set ``True``. + This means that messages parsed with a Bytes parser that have a :mailheader:`Content-Transfer-Encoding` of 8bit will be converted to a use a 7bit Content-Transfer-Encoding. Non-ASCII bytes in the headers will be :rfc:`2047` encoded with a charset of `unknown-8bit`. @@ -103,7 +111,8 @@ formatted string representation of a message object. For more detail, see :mod:`email.message`. -.. class:: BytesGenerator(outfp, mangle_from_=True, maxheaderlen=78) +.. class:: BytesGenerator(outfp, mangle_from_=True, maxheaderlen=78, *, \ + policy=policy.default) The constructor for the :class:`BytesGenerator` class takes a binary :term:`file-like object` called *outfp* for an argument. *outfp* must @@ -125,19 +134,31 @@ wrapping. The default is 78, as recommended (but not required) by :rfc:`2822`. + The *policy* keyword specifies a :mod:`~email.policy` object that controls a + number of aspects of the generator's operation. The default policy + maintains backward compatibility. + + .. versionchanged:: 3.3 Added the *policy* keyword. + The other public :class:`BytesGenerator` methods are: - .. method:: flatten(msg, unixfrom=False, linesep='\n') + .. method:: flatten(msg, unixfrom=False, linesep=None) Print the textual representation of the message object structure rooted at *msg* to the output file specified when the :class:`BytesGenerator` instance was created. Subparts are visited depth-first and the resulting - text will be properly MIME encoded. If the input that created the *msg* - contained bytes with the high bit set and those bytes have not been - modified, they will be copied faithfully to the output, even if doing so - is not strictly RFC compliant. (To produce strictly RFC compliant - output, use the :class:`Generator` class.) + text will be properly MIME encoded. If the :mod:`~email.policy` option + :attr:`~email.policy.Policy.must_be_7bit` is ``False`` (the default), + then any bytes with the high bit set in the original parsed message that + have not been modified will be copied faithfully to the output. If + ``must_be_7bit`` is true, the bytes will be converted as needed using an + ASCII content-transfer-encoding. In particular, RFC-invalid non-ASCII + bytes in headers will be encoded using the MIME ``unknown-8bit`` + character set, thus rendering them RFC-compliant. + + .. XXX: There should be a complementary option that just does the RFC + compliance transformation but leaves CTE 8bit parts alone. Messages parsed with a Bytes parser that have a :mailheader:`Content-Transfer-Encoding` of 8bit will be reconstructed @@ -152,10 +173,8 @@ Note that for subparts, no envelope header is ever printed. Optional *linesep* specifies the line separator character used to - terminate lines in the output. It defaults to ``\n`` because that is - the most useful value for Python application code (other library packages - expect ``\n`` separated lines). ``linesep=\r\n`` can be used to - generate output with RFC-compliant line separators. + terminate lines in the output. If specified it overrides the value + specified by the ``Generator``\ 's ``policy``. .. method:: clone(fp) diff --git a/Doc/library/email.parser.rst b/Doc/library/email.parser.rst --- a/Doc/library/email.parser.rst +++ b/Doc/library/email.parser.rst @@ -58,12 +58,18 @@ Here is the API for the :class:`FeedParser`: -.. class:: FeedParser(_factory=email.message.Message) +.. class:: FeedParser(_factory=email.message.Message, *, policy=policy.default) Create a :class:`FeedParser` instance. Optional *_factory* is a no-argument callable that will be called whenever a new message object is needed. It defaults to the :class:`email.message.Message` class. + The *policy* keyword specifies a :mod:`~email.policy` object that controls a + number of aspects of the parser's operation. The default policy maintains + backward compatibility. + + .. versionchanged:: 3.3 Added the *policy* keyword. + .. method:: feed(data) Feed the :class:`FeedParser` some more data. *data* should be a string @@ -104,7 +110,7 @@ .. versionadded:: 3.3 BytesHeaderParser -.. class:: Parser(_class=email.message.Message) +.. class:: Parser(_class=email.message.Message, *, policy=policy.default) The constructor for the :class:`Parser` class takes an optional argument *_class*. This must be a callable factory (such as a function or a class), and @@ -112,8 +118,13 @@ :class:`~email.message.Message` (see :mod:`email.message`). The factory will be called without arguments. - .. versionchanged:: 3.2 - Removed the *strict* argument that was deprecated in 2.4. + The *policy* keyword specifies a :mod:`~email.policy` object that controls a + number of aspects of the parser's operation. The default policy maintains + backward compatibility. + + .. versionchanged:: 3.3 + Removed the *strict* argument that was deprecated in 2.4. Added the + *policy* keyword. The other public :class:`Parser` methods are: @@ -144,12 +155,18 @@ the entire contents of the file. -.. class:: BytesParser(_class=email.message.Message, strict=None) +.. class:: BytesParser(_class=email.message.Message, *, policy=policy.default) This class is exactly parallel to :class:`Parser`, but handles bytes input. The *_class* and *strict* arguments are interpreted in the same way as for - the :class:`Parser` constructor. *strict* is supported only to make porting - code easier; it is deprecated. + the :class:`Parser` constructor. + + The *policy* keyword specifies a :mod:`~email.policy` object that + controls a number of aspects of the parser's operation. The default + policy maintains backward compatibility. + + .. versionchanged:: 3.3 + Removed the *strict* argument. Added the *policy* keyword. .. method:: parse(fp, headeronly=False) @@ -187,12 +204,15 @@ .. currentmodule:: email -.. function:: message_from_string(s, _class=email.message.Message, strict=None) +.. function:: message_from_string(s, _class=email.message.Message, *, \ + policy=policy.default) Return a message object structure from a string. This is exactly equivalent to - ``Parser().parsestr(s)``. Optional *_class* and *strict* are interpreted as + ``Parser().parsestr(s)``. *_class* and *policy* are interpreted as with the :class:`Parser` class constructor. + .. versionchanged:: removed *strict*, added *policy* + .. function:: message_from_bytes(s, _class=email.message.Message, strict=None) Return a message object structure from a byte string. This is exactly @@ -200,21 +220,27 @@ *strict* are interpreted as with the :class:`Parser` class constructor. .. versionadded:: 3.2 + .. versionchanged:: 3.3 removed *strict*, added *policy* -.. function:: message_from_file(fp, _class=email.message.Message, strict=None) +.. function:: message_from_file(fp, _class=email.message.Message, *, \ + policy=policy.default) Return a message object structure tree from an open :term:`file object`. - This is exactly equivalent to ``Parser().parse(fp)``. Optional *_class* - and *strict* are interpreted as with the :class:`Parser` class constructor. + This is exactly equivalent to ``Parser().parse(fp)``. *_class* + and *policy* are interpreted as with the :class:`Parser` class constructor. -.. function:: message_from_binary_file(fp, _class=email.message.Message, strict=None) + .. versionchanged:: 3.3 removed *strict*, added *policy* + +.. function:: message_from_binary_file(fp, _class=email.message.Message, *, \ + policy=policy.default) Return a message object structure tree from an open binary :term:`file object`. This is exactly equivalent to ``BytesParser().parse(fp)``. - Optional *_class* and *strict* are interpreted as with the :class:`Parser` + *_class* and *policy* are interpreted as with the :class:`Parser` class constructor. .. versionadded:: 3.2 + .. versionchanged:: 3.3 removed *strict*, added *policy* Here's an example of how you might use this at an interactive Python prompt:: diff --git a/Doc/library/email.policy.rst b/Doc/library/email.policy.rst new file mode 100644 --- /dev/null +++ b/Doc/library/email.policy.rst @@ -0,0 +1,179 @@ +:mod:`email`: Policy Objects +---------------------------- + +.. module:: email.policy + :synopsis: Controlling the parsing and generating of messages + + +The :mod:`email` package's prime focus is the handling of email messages as +described by the various email and MIME RFCs. However, the general format of +email messages (a block of header fields each consisting of a name followed by +a colon followed by a value, the whole block followed by a blank line and an +arbitrary 'body'), is a format that has found utility outside of the realm of +email. Some of these uses conform fairly closely to the main RFCs, some do +not. And even when working with email, there are times when it is desirable to +break strict compliance with the RFCs. + +Policy objects are the mechanism used to provide the email package with the +flexibility to handle all these disparate use cases, + +A :class:`Policy` object encapsulates a set of attributes and methods that +control the behavior of various components of the email package during use. +:class:`Policy` instances can be passed to various classes and methods in the +email package to alter the default behavior. The settable values and their +defaults are described below. The :mod:`policy` module also provides some +pre-created :class:`Policy` instances. In addition to a :const:`default` +instance, there are instances tailored for certain applications. For example +there is an :const:`SMTP` :class:`Policy` with defaults appropriate for +generating output to be sent to an SMTP server. These are listed :ref:`below +`. + +In general an application will only need to deal with setting the policy at the +input and output boundaries. Once parsed, a message is represented by a +:class:`~email.message.Message` object, which is designed to be independent of +the format that the message has "on the wire" when it is received, transmitted, +or displayed. Thus, a :class:`Policy` can be specified when parsing a message +to create a :class:`~email.message.Message`, and again when turning the +:class:`~email.message.Message` into some other representation. While often a +program will use the same :class:`Policy` for both input and output, the two +can be different. + +As an example, the following code could be used to read an email message from a +file on disk and pass it to the system ``sendmail`` program on a ``unix`` +system:: + + >>> from email import msg_from_binary_file + >>> from email.generator import BytesGenerator + >>> import email.policy + >>> from subprocess import Popen, PIPE + >>> with open('mymsg.txt', 'b') as f: + >>> msg = msg_from_binary_file(f, policy=email.policy.mbox) + >>> p = Popen(['sendmail', msg['To'][0].address], stdin=PIPE) + >>> g = BytesGenerator(p.stdin, email.policy.policy=SMTP) + >>> g.flatten(msg) + >>> p.stdin.close() + >>> rc = p.wait() + +Some email package methods accept a *policy* keyword argument, allowing the +policy to be overridden for that method. For example, the following code use +the :meth:`email.message.Message.as_string` method to the *msg* object from the +previous example and re-write it to a file using the native line separators for +the platform on which it is running:: + + >>> import os + >>> mypolicy = email.policy.Policy(linesep=os.linesep) + >>> with open('converted.txt', 'wb') as f: + ... f.write(msg.as_string(policy=mypolicy)) + +Policy instances are immutable, but they can be cloned, accepting the same +keyword arguments as the class constructor and returning a new :class:`Policy` +instance that is a copy of the original but with the specified attributes +values changed. For example, the following creates an SMTP policy that will +raise any defects detected as errors:: + + >>> strict_SMTP = email.policy.SMTP.clone(raise_on_defect=True) + +Policy objects can also be combined using the addition operator, producing a +policy object whose settings are a combination of the non-default values of the +summed objects:: + + >>> strict_SMTP = email.policy.SMTP + email.policy.strict + +This operation is not commutative; that is, the order in which the objects are +added matters. To illustrate:: + + >>> Policy = email.policy.Policy + >>> apolicy = Policy(max_line_length=100) + Policy(max_line_length=80) + >>> apolicy.max_line_length + 80 + >>> apolicy = Policy(max_line_length=80) + Policy(max_line_length=100) + >>> apolicy.max_line_length + 100 + + +.. class:: Policy(**kw) + + The valid constructor keyword arguments are any of the attributes listed + below. + + .. attribute:: max_line_length + + The maximum length of any line in the serialized output, not counting the + end of line character(s). Default is 78, per :rfc:`5322`. A value of + ``0`` or :const:`None` indicates that no line wrapping should be + done at all. + + .. attribute:: linesep + + The string to be used to terminate lines in serialized output. The + default is '\\n' because that's the internal end-of-line discipline used + by Python, though '\\r\\n' is required by the RFCs. See `Policy + Instances`_ for policies that use an RFC conformant linesep. Setting it + to :attr:`os.linesep` may also be useful. + + .. attribute:: must_be_7bit + + If :const:`True`, data output by a bytes generator is limited to ASCII + characters. If :const:`False` (the default), then bytes with the high + bit set are preserved and/or allowed in certain contexts (for example, + where possible a content transfer encoding of ``8bit`` will be used). + String generators act as if ``must_be_7bit`` is `True` regardless of the + policy in effect, since a string cannot represent non-ASCII bytes. + + .. attribute:: raise_on_defect + + If :const:`True`, any defects encountered will be raised as errors. If + :const:`False` (the default), defects will be passed to the + :meth:`register_defect` method. + + .. method:: handle_defect(obj, defect) + + *obj* is the object on which to register the defect. *defect* should be + an instance of a subclass of :class:`~email.errors.Defect`. + If :attr:`raise_on_defect` + is ``True`` the defect is raised as an exception. Otherwise *obj* and + *defect* are passed to :meth:`register_defect`. This method is intended + to be called by parsers when they encounter defects, and will not be + called by code that uses the email library unless that code is + implementing an alternate parser. + + .. method:: register_defect(obj, defect) + + *obj* is the object on which to register the defect. *defect* should be + a subclass of :class:`~email.errors.Defect`. This method is part of the + public API so that custom ``Policy`` subclasses can implement alternate + handling of defects. The default implementation calls the ``append`` + method of the ``defects`` attribute of *obj*. + + .. method:: clone(obj, *kw): + + Return a new :class:`Policy` instance whose attributes have the same + values as the current instance, except where those attributes are + given new values by the keyword arguments. + + +Policy Instances +................ + +The following instances of :class:`Policy` provide defaults suitable for +specific common application domains. + +.. data:: default + + An instance of :class:`Policy` with all defaults unchanged. + +.. data:: SMTP + + Output serialized from a message will conform to the email and SMTP + RFCs. The only changed attribute is :attr:`linesep`, which is set to + ``\r\n``. + +.. data:: HTTP + + Suitable for use when serializing headers for use in HTTP traffic. + :attr:`linesep` is set to ``\r\n``, and :attr:`max_line_length` is set to + :const:`None` (unlimited). + +.. data:: strict + + :attr:`raise_on_defect` is set to :const:`True`. diff --git a/Lib/email/errors.py b/Lib/email/errors.py --- a/Lib/email/errors.py +++ b/Lib/email/errors.py @@ -32,7 +32,7 @@ # These are parsing defects which the parser was able to work around. -class MessageDefect: +class MessageDefect(Exception): """Base class for a message defect.""" def __init__(self, line=None): diff --git a/Lib/email/feedparser.py b/Lib/email/feedparser.py --- a/Lib/email/feedparser.py +++ b/Lib/email/feedparser.py @@ -25,6 +25,7 @@ from email import errors from email import message +from email import policy NLCRE = re.compile('\r\n|\r|\n') NLCRE_bol = re.compile('(\r\n|\r|\n)') @@ -134,9 +135,16 @@ class FeedParser: """A feed-style parser of email.""" - def __init__(self, _factory=message.Message): - """_factory is called with no arguments to create a new message obj""" + def __init__(self, _factory=message.Message, *, policy=policy.default): + """_factory is called with no arguments to create a new message obj + + The policy keyword specifies a policy object that controls a number of + aspects of the parser's operation. The default policy maintains + backward compatibility. + + """ self._factory = _factory + self.policy = policy self._input = BufferedSubFile() self._msgstack = [] self._parse = self._parsegen().__next__ @@ -168,7 +176,8 @@ # Look for final set of defects if root.get_content_maintype() == 'multipart' \ and not root.is_multipart(): - root.defects.append(errors.MultipartInvariantViolationDefect()) + defect = errors.MultipartInvariantViolationDefect() + self.policy.handle_defect(root, defect) return root def _new_message(self): @@ -281,7 +290,8 @@ # defined a boundary. That's a problem which we'll handle by # reading everything until the EOF and marking the message as # defective. - self._cur.defects.append(errors.NoBoundaryInMultipartDefect()) + defect = errors.NoBoundaryInMultipartDefect() + self.policy.handle_defect(self._cur, defect) lines = [] for line in self._input: if line is NeedMoreData: @@ -385,7 +395,8 @@ # that as a defect and store the captured text as the payload. # Everything from here to the EOF is epilogue. if capturing_preamble: - self._cur.defects.append(errors.StartBoundaryNotFoundDefect()) + defect = errors.StartBoundaryNotFoundDefect() + self.policy.handle_defect(self._cur, defect) self._cur.set_payload(EMPTYSTRING.join(preamble)) epilogue = [] for line in self._input: @@ -437,7 +448,7 @@ # is illegal, so let's note the defect, store the illegal # line, and ignore it for purposes of headers. defect = errors.FirstHeaderLineIsContinuationDefect(line) - self._cur.defects.append(defect) + self.policy.handle_defect(self._cur, defect) continue lastvalue.append(line) continue diff --git a/Lib/email/generator.py b/Lib/email/generator.py --- a/Lib/email/generator.py +++ b/Lib/email/generator.py @@ -13,8 +13,10 @@ import warnings from io import StringIO, BytesIO +from email import policy from email.header import Header from email.message import _has_surrogates +import email.charset as _charset UNDERSCORE = '_' NL = '\n' # XXX: no longer used by the code below. @@ -33,7 +35,8 @@ # Public interface # - def __init__(self, outfp, mangle_from_=True, maxheaderlen=78): + def __init__(self, outfp, mangle_from_=True, maxheaderlen=None, *, + policy=policy.default): """Create the generator for message flattening. outfp is the output file-like object for writing the message to. It @@ -49,16 +52,23 @@ defined in the Header class. Set maxheaderlen to zero to disable header wrapping. The default is 78, as recommended (but not required) by RFC 2822. + + The policy keyword specifies a policy object that controls a number of + aspects of the generator's operation. The default policy maintains + backward compatibility. + """ self._fp = outfp self._mangle_from_ = mangle_from_ - self._maxheaderlen = maxheaderlen + self._maxheaderlen = (maxheaderlen if maxheaderlen is not None else + policy.max_line_length) + self.policy = policy def write(self, s): # Just delegate to the file object self._fp.write(s) - def flatten(self, msg, unixfrom=False, linesep='\n'): + def flatten(self, msg, unixfrom=False, linesep=None): r"""Print the message object tree rooted at msg to the output file specified when the Generator instance was created. @@ -70,17 +80,15 @@ Note that for subobjects, no From_ line is printed. linesep specifies the characters used to indicate a new line in - the output. The default value is the most useful for typical - Python applications, but it can be set to \r\n to produce RFC-compliant - line separators when needed. + the output. The default value is determined by the policy. """ # We use the _XXX constants for operating on data that comes directly # from the msg, and _encoded_XXX constants for operating on data that # has already been converted (to bytes in the BytesGenerator) and # inserted into a temporary buffer. - self._NL = linesep - self._encoded_NL = self._encode(linesep) + self._NL = linesep if linesep is not None else self.policy.linesep + self._encoded_NL = self._encode(self._NL) self._EMPTY = '' self._encoded_EMTPY = self._encode('') if unixfrom: @@ -338,7 +346,10 @@ Functionally identical to the base Generator except that the output is bytes and not string. When surrogates were used in the input to encode - bytes, these are decoded back to bytes for output. + bytes, these are decoded back to bytes for output. If the policy has + must_be_7bit set true, then the message is transformed such that the + non-ASCII bytes are properly content transfer encoded, using the + charset unknown-8bit. The outfp object must accept bytes in its write method. """ @@ -361,21 +372,22 @@ # strings with 8bit bytes. for h, v in msg._headers: self.write('%s: ' % h) - if isinstance(v, Header): - self.write(v.encode(maxlinelen=self._maxheaderlen)+NL) - elif _has_surrogates(v): - # If we have raw 8bit data in a byte string, we have no idea - # what the encoding is. There is no safe way to split this - # string. If it's ascii-subset, then we could do a normal - # ascii split, but if it's multibyte then we could break the - # string. There's no way to know so the least harm seems to - # be to not split the string and risk it being too long. - self.write(v+NL) - else: - # Header's got lots of smarts and this string is safe... - header = Header(v, maxlinelen=self._maxheaderlen, - header_name=h) - self.write(header.encode(linesep=self._NL)+self._NL) + if isinstance(v, str): + if _has_surrogates(v): + if not self.policy.must_be_7bit: + # If we have raw 8bit data in a byte string, we have no idea + # what the encoding is. There is no safe way to split this + # string. If it's ascii-subset, then we could do a normal + # ascii split, but if it's multibyte then we could break the + # string. There's no way to know so the least harm seems to + # be to not split the string and risk it being too long. + self.write(v+NL) + continue + h = Header(v, charset=_charset.UNKNOWN8BIT, header_name=h) + else: + h = Header(v, header_name=h) + self.write(h.encode(linesep=self._NL, + maxlinelen=self._maxheaderlen)+self._NL) # A blank line always separates headers from body self.write(self._NL) @@ -384,7 +396,7 @@ # just write it back out. if msg._payload is None: return - if _has_surrogates(msg._payload): + if _has_surrogates(msg._payload) and not self.policy.must_be_7bit: self.write(msg._payload) else: super(BytesGenerator,self)._handle_text(msg) diff --git a/Lib/email/parser.py b/Lib/email/parser.py --- a/Lib/email/parser.py +++ b/Lib/email/parser.py @@ -11,11 +11,12 @@ from email.feedparser import FeedParser from email.message import Message +from email import policy class Parser: - def __init__(self, _class=Message): + def __init__(self, _class=Message, *, policy=policy.default): """Parser of RFC 2822 and MIME email messages. Creates an in-memory object tree representing the email message, which @@ -30,8 +31,14 @@ _class is the class to instantiate for new message objects when they must be created. This class must have a constructor that can take zero arguments. Default is Message.Message. + + The policy keyword specifies a policy object that controls a number of + aspects of the parser's operation. The default policy maintains + backward compatibility. + """ self._class = _class + self.policy = policy def parse(self, fp, headersonly=False): """Create a message structure from the data in a file. @@ -41,7 +48,7 @@ parsing after reading the headers or not. The default is False, meaning it parses the entire contents of the file. """ - feedparser = FeedParser(self._class) + feedparser = FeedParser(self._class, policy=self.policy) if headersonly: feedparser._set_headersonly() while True: diff --git a/Lib/email/policy.py b/Lib/email/policy.py new file mode 100644 --- /dev/null +++ b/Lib/email/policy.py @@ -0,0 +1,174 @@ +"""Policy framework for the email package. + +Allows fine grained feature control of how the package parses and emits data. +""" + +__all__ = [ + 'Policy', + 'default', + 'strict', + 'SMTP', + 'HTTP', + ] + + +class _PolicyBase: + + """Policy Object basic framework. + + This class is useless unless subclassed. A subclass should define + class attributes with defaults for any values that are to be + managed by the Policy object. The constructor will then allow + non-default values to be set for these attributes at instance + creation time. The instance will be callable, taking these same + attributes keyword arguments, and returning a new instance + identical to the called instance except for those values changed + by the keyword arguments. Instances may be added, yielding new + instances with any non-default values from the right hand + operand overriding those in the left hand operand. That is, + + A + B == A() + + The repr of an instance can be used to reconstruct the object + if and only if the repr of the values can be used to reconstruct + those values. + + """ + + def __init__(self, **kw): + """Create new Policy, possibly overriding some defaults. + + See class docstring for a list of overridable attributes. + + """ + for name, value in kw.items(): + if hasattr(self, name): + super(_PolicyBase,self).__setattr__(name, value) + else: + raise TypeError( + "{!r} is an invalid keyword argument for {}".format( + name, self.__class__.__name__)) + + def __repr__(self): + args = [ "{}={!r}".format(name, value) + for name, value in self.__dict__.items() ] + return "{}({})".format(self.__class__.__name__, args if args else '') + + def clone(self, **kw): + """Return a new instance with specified attributes changed. + + The new instance has the same attribute values as the current object, + except for the changes passed in as keyword arguments. + + """ + for attr, value in self.__dict__.items(): + if attr not in kw: + kw[attr] = value + return self.__class__(**kw) + + def __setattr__(self, name, value): + if hasattr(self, name): + msg = "{!r} object attribute {!r} is read-only" + else: + msg = "{!r} object has no attribute {!r}" + raise AttributeError(msg.format(self.__class__.__name__, name)) + + def __add__(self, other): + """Non-default values from right operand override those from left. + + The object returned is a new instance of the subclass. + + """ + return self.clone(**other.__dict__) + + +class Policy(_PolicyBase): + + """Controls for how messages are interpreted and formatted. + + Most of the classes and many of the methods in the email package + accept Policy objects as parameters. A Policy object contains a set + of values and functions that control how input is interpreted and how + output is rendered. For example, the parameter 'raise_on_defect' + controls whether or not an RFC violation throws an error or not, + while 'max_line_length' controls the maximum length of output lines + when a Message is serialized. + + Any valid attribute may be overridden when a Policy is created by + passing it as a keyword argument to the constructor. Policy + objects are immutable, but a new Policy object can be created + with only certain values changed by calling the Policy instance + with keyword arguments. Policy objects can also be added, + producing a new Policy object in which the non-default attributes + set in the right hand operand overwrite those specified in the + left operand. + + Settable attributes: + + raise_on_defect -- If true, then defects should be raised + as errors. Default False. + + linesep -- string containing the value to use as + separation between output lines. Default '\n'. + + must_be_7bit -- output must contain only 7bit clean data. + Default False. + + max_line_length -- maximum length of lines, excluding 'linesep', + during serialization. None means no line + wrapping is done. Default is 78. + + Methods: + + register_defect(obj, defect) + defect is a Defect instance. The default implementation appends defect + to the objs 'defects' attribute. + + handle_defect(obj, defect) + intended to be called by parser code that finds a defect. If + raise_on_defect is True, defect is raised as an error, otherwise + register_defect is called. + + """ + + raise_on_defect = False + linesep = '\n' + must_be_7bit = False + max_line_length = 78 + + def handle_defect(self, obj, defect): + """Based on policy, either raise defect or call register_defect. + + handle_defect(obj, defect) + + defect should be a Defect subclass, but in any case must be an + Exception subclass. obj is the object on which the defect should be + registered if it is not raised. If the raise_on_defect is True, the + defect is raised as an error, otherwise the object and the defect are + passed to register_defect. + + This class is intended to be called by parsers that discover defects, + and will not be called from code using the library unless that code is + implementing an alternate parser. + + """ + if self.raise_on_defect: + raise defect + self.register_defect(obj, defect) + + def register_defect(self, obj, defect): + """Record 'defect' on 'obj'. + + Called by handle_defect if raise_on_defect is False. This method is + part of the Policy API so that Policy subclasses can implement custom + defect handling. The default implementation calls the append method + of the defects attribute of obj. + + """ + obj.defects.append(defect) + + +default = Policy() +strict = default.clone(raise_on_defect=True) +SMTP = default.clone(linesep='\r\n') +HTTP = default.clone(linesep='\r\n', max_line_length=None) diff --git a/Lib/test/test_email/__init__.py b/Lib/test/test_email/__init__.py --- a/Lib/test/test_email/__init__.py +++ b/Lib/test/test_email/__init__.py @@ -25,6 +25,8 @@ # Base test class class TestEmailBase(unittest.TestCase): + maxDiff = None + def __init__(self, *args, **kw): super().__init__(*args, **kw) self.addTypeEqualityFunc(bytes, self.assertBytesEqual) diff --git a/Lib/test/test_email/test_email.py b/Lib/test/test_email/test_email.py --- a/Lib/test/test_email/test_email.py +++ b/Lib/test/test_email/test_email.py @@ -1776,7 +1776,12 @@ # Test some badly formatted messages -class TestNonConformant(TestEmailBase): +class TestNonConformantBase: + + def _msgobj(self, filename): + with openfile(filename) as fp: + return email.message_from_file(fp, policy=self.policy) + def test_parse_missing_minor_type(self): eq = self.assertEqual msg = self._msgobj('msg_14.txt') @@ -1790,17 +1795,18 @@ # XXX We can probably eventually do better inner = msg.get_payload(0) unless(hasattr(inner, 'defects')) - self.assertEqual(len(inner.defects), 1) - unless(isinstance(inner.defects[0], + self.assertEqual(len(self.get_defects(inner)), 1) + unless(isinstance(self.get_defects(inner)[0], errors.StartBoundaryNotFoundDefect)) def test_multipart_no_boundary(self): unless = self.assertTrue msg = self._msgobj('msg_25.txt') unless(isinstance(msg.get_payload(), str)) - self.assertEqual(len(msg.defects), 2) - unless(isinstance(msg.defects[0], errors.NoBoundaryInMultipartDefect)) - unless(isinstance(msg.defects[1], + self.assertEqual(len(self.get_defects(msg)), 2) + unless(isinstance(self.get_defects(msg)[0], + errors.NoBoundaryInMultipartDefect)) + unless(isinstance(self.get_defects(msg)[1], errors.MultipartInvariantViolationDefect)) def test_invalid_content_type(self): @@ -1856,9 +1862,10 @@ unless = self.assertTrue msg = self._msgobj('msg_41.txt') unless(hasattr(msg, 'defects')) - self.assertEqual(len(msg.defects), 2) - unless(isinstance(msg.defects[0], errors.NoBoundaryInMultipartDefect)) - unless(isinstance(msg.defects[1], + self.assertEqual(len(self.get_defects(msg)), 2) + unless(isinstance(self.get_defects(msg)[0], + errors.NoBoundaryInMultipartDefect)) + unless(isinstance(self.get_defects(msg)[1], errors.MultipartInvariantViolationDefect)) def test_missing_start_boundary(self): @@ -1872,21 +1879,71 @@ # # [*] This message is missing its start boundary bad = outer.get_payload(1).get_payload(0) - self.assertEqual(len(bad.defects), 1) - self.assertTrue(isinstance(bad.defects[0], + self.assertEqual(len(self.get_defects(bad)), 1) + self.assertTrue(isinstance(self.get_defects(bad)[0], errors.StartBoundaryNotFoundDefect)) def test_first_line_is_continuation_header(self): eq = self.assertEqual m = ' Line 1\nLine 2\nLine 3' - msg = email.message_from_string(m) + msg = email.message_from_string(m, policy=self.policy) eq(msg.keys(), []) eq(msg.get_payload(), 'Line 2\nLine 3') - eq(len(msg.defects), 1) - self.assertTrue(isinstance(msg.defects[0], + eq(len(self.get_defects(msg)), 1) + self.assertTrue(isinstance(self.get_defects(msg)[0], errors.FirstHeaderLineIsContinuationDefect)) - eq(msg.defects[0].line, ' Line 1\n') - + eq(self.get_defects(msg)[0].line, ' Line 1\n') + + +class TestNonConformant(TestNonConformantBase, TestEmailBase): + + policy=email.policy.default + + def get_defects(self, obj): + return obj.defects + + +class TestNonConformantCapture(TestNonConformantBase, TestEmailBase): + + class CapturePolicy(email.policy.Policy): + captured = None + def register_defect(self, obj, defect): + self.captured.append(defect) + + def setUp(self): + self.policy = self.CapturePolicy(captured=list()) + + def get_defects(self, obj): + return self.policy.captured + + +class TestRaisingDefects(TestEmailBase): + + def _msgobj(self, filename): + with openfile(filename) as fp: + return email.message_from_file(fp, policy=email.policy.strict) + + def test_same_boundary_inner_outer(self): + with self.assertRaises(errors.StartBoundaryNotFoundDefect): + self._msgobj('msg_15.txt') + + def test_multipart_no_boundary(self): + with self.assertRaises(errors.NoBoundaryInMultipartDefect): + self._msgobj('msg_25.txt') + + def test_lying_multipart(self): + with self.assertRaises(errors.NoBoundaryInMultipartDefect): + self._msgobj('msg_41.txt') + + + def test_missing_start_boundary(self): + with self.assertRaises(errors.StartBoundaryNotFoundDefect): + self._msgobj('msg_42.txt') + + def test_first_line_is_continuation_header(self): + m = ' Line 1\nLine 2\nLine 3' + with self.assertRaises(errors.FirstHeaderLineIsContinuationDefect): + msg = email.message_from_string(m, policy=email.policy.strict) # Test RFC 2047 header encoding and decoding @@ -2997,6 +3054,25 @@ g.flatten(msg, linesep='\r\n') self.assertEqual(s.getvalue(), text) + def test_crlf_control_via_policy(self): + with openfile('msg_26.txt', newline='\n') as fp: + text = fp.read() + msg = email.message_from_string(text) + s = StringIO() + g = email.generator.Generator(s, policy=email.policy.SMTP) + g.flatten(msg) + self.assertEqual(s.getvalue(), text) + + def test_flatten_linesep_overrides_policy(self): + # msg_27 is lf separated + with openfile('msg_27.txt', newline='\n') as fp: + text = fp.read() + msg = email.message_from_string(text) + s = StringIO() + g = email.generator.Generator(s, policy=email.policy.SMTP) + g.flatten(msg, linesep='\n') + self.assertEqual(s.getvalue(), text) + maxDiff = None def test_multipart_digest_with_extra_mime_headers(self): @@ -3463,6 +3539,44 @@ g.flatten(msg) self.assertEqual(s.getvalue(), source) + def test_crlf_control_via_policy(self): + # msg_26 is crlf terminated + with openfile('msg_26.txt', 'rb') as fp: + text = fp.read() + msg = email.message_from_bytes(text) + s = BytesIO() + g = email.generator.BytesGenerator(s, policy=email.policy.SMTP) + g.flatten(msg) + self.assertEqual(s.getvalue(), text) + + def test_flatten_linesep_overrides_policy(self): + # msg_27 is lf separated + with openfile('msg_27.txt', 'rb') as fp: + text = fp.read() + msg = email.message_from_bytes(text) + s = BytesIO() + g = email.generator.BytesGenerator(s, policy=email.policy.SMTP) + g.flatten(msg, linesep='\n') + self.assertEqual(s.getvalue(), text) + + def test_must_be_7bit_handles_unknown_8bit(self): + msg = email.message_from_bytes(self.non_latin_bin_msg) + out = BytesIO() + g = email.generator.BytesGenerator(out, + policy=email.policy.default.clone(must_be_7bit=True)) + g.flatten(msg) + self.assertEqual(out.getvalue(), + self.non_latin_bin_msg_as7bit_wrapped.encode('ascii')) + + def test_must_be_7bit_transforms_8bit_cte(self): + msg = email.message_from_bytes(self.latin_bin_msg) + out = BytesIO() + g = email.generator.BytesGenerator(out, + policy=email.policy.default.clone(must_be_7bit=True)) + g.flatten(msg) + self.assertEqual(out.getvalue(), + self.latin_bin_msg_as7bit.encode('ascii')) + maxDiff = None diff --git a/Lib/test/test_email/test_generator.py b/Lib/test/test_email/test_generator.py new file mode 100644 --- /dev/null +++ b/Lib/test/test_email/test_generator.py @@ -0,0 +1,136 @@ +import io +import textwrap +import unittest +from email import message_from_string, message_from_bytes +from email.generator import Generator, BytesGenerator +from email import policy +from test.test_email import TestEmailBase + +# XXX: move generator tests from test_email into here at some point. + + +class TestGeneratorBase(): + + long_subject = { + 0: textwrap.dedent("""\ + To: whom_it_may_concern at example.com + From: nobody_you_want_to_know at example.com + Subject: We the willing led by the unknowing are doing the + impossible for the ungrateful. We have done so much for so long with so little + we are now qualified to do anything with nothing. + + None + """), + 40: textwrap.dedent("""\ + To: whom_it_may_concern at example.com + From:\x20 + nobody_you_want_to_know at example.com + Subject: We the willing led by the + unknowing are doing the + impossible for the ungrateful. We have + done so much for so long with so little + we are now qualified to do anything + with nothing. + + None + """), + 20: textwrap.dedent("""\ + To:\x20 + whom_it_may_concern at example.com + From:\x20 + nobody_you_want_to_know at example.com + Subject: We the + willing led by the + unknowing are doing + the + impossible for the + ungrateful. We have + done so much for so + long with so little + we are now + qualified to do + anything with + nothing. + + None + """), + } + long_subject[100] = long_subject[0] + + def maxheaderlen_parameter_test(self, n): + msg = self.msgmaker(self.long_subject[0]) + s = self.ioclass() + g = self.genclass(s, maxheaderlen=n) + g.flatten(msg) + self.assertEqual(s.getvalue(), self.long_subject[n]) + + def test_maxheaderlen_parameter_0(self): + self.maxheaderlen_parameter_test(0) + + def test_maxheaderlen_parameter_100(self): + self.maxheaderlen_parameter_test(100) + + def test_maxheaderlen_parameter_40(self): + self.maxheaderlen_parameter_test(40) + + def test_maxheaderlen_parameter_20(self): + self.maxheaderlen_parameter_test(20) + + def maxheaderlen_policy_test(self, n): + msg = self.msgmaker(self.long_subject[0]) + s = self.ioclass() + g = self.genclass(s, policy=policy.default.clone(max_line_length=n)) + g.flatten(msg) + self.assertEqual(s.getvalue(), self.long_subject[n]) + + def test_maxheaderlen_policy_0(self): + self.maxheaderlen_policy_test(0) + + def test_maxheaderlen_policy_100(self): + self.maxheaderlen_policy_test(100) + + def test_maxheaderlen_policy_40(self): + self.maxheaderlen_policy_test(40) + + def test_maxheaderlen_policy_20(self): + self.maxheaderlen_policy_test(20) + + def maxheaderlen_parm_overrides_policy_test(self, n): + msg = self.msgmaker(self.long_subject[0]) + s = self.ioclass() + g = self.genclass(s, maxheaderlen=n, + policy=policy.default.clone(max_line_length=10)) + g.flatten(msg) + self.assertEqual(s.getvalue(), self.long_subject[n]) + + def test_maxheaderlen_parm_overrides_policy_0(self): + self.maxheaderlen_parm_overrides_policy_test(0) + + def test_maxheaderlen_parm_overrides_policy_100(self): + self.maxheaderlen_parm_overrides_policy_test(100) + + def test_maxheaderlen_parm_overrides_policy_40(self): + self.maxheaderlen_parm_overrides_policy_test(40) + + def test_maxheaderlen_parm_overrides_policy_20(self): + self.maxheaderlen_parm_overrides_policy_test(20) + + +class TestGenerator(TestGeneratorBase, TestEmailBase): + + msgmaker = staticmethod(message_from_string) + genclass = Generator + ioclass = io.StringIO + + +class TestBytesGenerator(TestGeneratorBase, TestEmailBase): + + msgmaker = staticmethod(message_from_bytes) + genclass = BytesGenerator + ioclass = io.BytesIO + long_subject = {key: x.encode('ascii') + for key, x in TestGeneratorBase.long_subject.items()} + + +if __name__ == '__main__': + unittest.main() diff --git a/Lib/test/test_email/test_policy.py b/Lib/test/test_email/test_policy.py new file mode 100644 --- /dev/null +++ b/Lib/test/test_email/test_policy.py @@ -0,0 +1,148 @@ +import types +import unittest +import email.policy + +class PolicyAPITests(unittest.TestCase): + + longMessage = True + + # These default values are the ones set on email.policy.default. + # If any of these defaults change, the docs must be updated. + policy_defaults = { + 'max_line_length': 78, + 'linesep': '\n', + 'must_be_7bit': False, + 'raise_on_defect': False, + } + + # For each policy under test, we give here the values of the attributes + # that are different from the defaults for that policy. + policies = { + email.policy.Policy(): {}, + email.policy.default: {}, + email.policy.SMTP: {'linesep': '\r\n'}, + email.policy.HTTP: {'linesep': '\r\n', 'max_line_length': None}, + email.policy.strict: {'raise_on_defect': True}, + } + + def test_defaults(self): + for policy, changed_defaults in self.policies.items(): + expected = self.policy_defaults.copy() + expected.update(changed_defaults) + for attr, value in expected.items(): + self.assertEqual(getattr(policy, attr), value, + ("change {} docs/docstrings if defaults have " + "changed").format(policy)) + + def test_all_attributes_covered(self): + for attr in dir(email.policy.default): + if (attr.startswith('_') or + isinstance(getattr(email.policy.Policy, attr), + types.FunctionType)): + continue + else: + self.assertIn(attr, self.policy_defaults, + "{} is not fully tested".format(attr)) + + def test_policy_is_immutable(self): + for policy in self.policies: + for attr in self.policy_defaults: + with self.assertRaisesRegex(AttributeError, attr+".*read-only"): + setattr(policy, attr, None) + with self.assertRaisesRegex(AttributeError, 'no attribute.*foo'): + policy.foo = None + + def test_set_policy_attrs_when_calledl(self): + testattrdict = { attr: None for attr in self.policy_defaults } + for policyclass in self.policies: + policy = policyclass.clone(**testattrdict) + for attr in self.policy_defaults: + self.assertIsNone(getattr(policy, attr)) + + def test_reject_non_policy_keyword_when_called(self): + for policyclass in self.policies: + with self.assertRaises(TypeError): + policyclass(this_keyword_should_not_be_valid=None) + with self.assertRaises(TypeError): + policyclass(newtline=None) + + def test_policy_addition(self): + expected = self.policy_defaults.copy() + p1 = email.policy.default.clone(max_line_length=100) + p2 = email.policy.default.clone(max_line_length=50) + added = p1 + p2 + expected.update(max_line_length=50) + for attr, value in expected.items(): + self.assertEqual(getattr(added, attr), value) + added = p2 + p1 + expected.update(max_line_length=100) + for attr, value in expected.items(): + self.assertEqual(getattr(added, attr), value) + added = added + email.policy.default + for attr, value in expected.items(): + self.assertEqual(getattr(added, attr), value) + + def test_register_defect(self): + class Dummy: + def __init__(self): + self.defects = [] + obj = Dummy() + defect = object() + policy = email.policy.Policy() + policy.register_defect(obj, defect) + self.assertEqual(obj.defects, [defect]) + defect2 = object() + policy.register_defect(obj, defect2) + self.assertEqual(obj.defects, [defect, defect2]) + + class MyObj: + def __init__(self): + self.defects = [] + + class MyDefect(Exception): + pass + + def test_handle_defect_raises_on_strict(self): + foo = self.MyObj() + defect = self.MyDefect("the telly is broken") + with self.assertRaisesRegex(self.MyDefect, "the telly is broken"): + email.policy.strict.handle_defect(foo, defect) + + def test_handle_defect_registers_defect(self): + foo = self.MyObj() + defect1 = self.MyDefect("one") + email.policy.default.handle_defect(foo, defect1) + self.assertEqual(foo.defects, [defect1]) + defect2 = self.MyDefect("two") + email.policy.default.handle_defect(foo, defect2) + self.assertEqual(foo.defects, [defect1, defect2]) + + class MyPolicy(email.policy.Policy): + defects = [] + def register_defect(self, obj, defect): + self.defects.append(defect) + + def test_overridden_register_defect_still_raises(self): + foo = self.MyObj() + defect = self.MyDefect("the telly is broken") + with self.assertRaisesRegex(self.MyDefect, "the telly is broken"): + self.MyPolicy(raise_on_defect=True).handle_defect(foo, defect) + + def test_overriden_register_defect_works(self): + foo = self.MyObj() + defect1 = self.MyDefect("one") + my_policy = self.MyPolicy() + my_policy.handle_defect(foo, defect1) + self.assertEqual(my_policy.defects, [defect1]) + self.assertEqual(foo.defects, []) + defect2 = self.MyDefect("two") + my_policy.handle_defect(foo, defect2) + self.assertEqual(my_policy.defects, [defect1, defect2]) + self.assertEqual(foo.defects, []) + + # XXX: Need subclassing tests. + # For adding subclassed objects, make sure the usual rules apply (subclass + # wins), but that the order still works (right overrides left). + +if __name__ == '__main__': + unittest.main() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -110,6 +110,9 @@ Library ------- +- Issue #11731: simplify/enhance email parser/generator API by introducing + policy objects. + - Issue #11768: The signal handler of the signal module only calls Py_AddPendingCall() for the first signal to fix a deadlock on reentrant or parallel calls. PyErr_SetInterrupt() writes also into the wake up file. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 18 20:30:13 2011 From: python-checkins at python.org (ned.deily) Date: Mon, 18 Apr 2011 20:30:13 +0200 Subject: [Python-checkins] devguide: Improve description of "svn-like" workflow. (Patch by Carl Meyer) Message-ID: http://hg.python.org/devguide/rev/cc43ed7af5f2 changeset: 414:cc43ed7af5f2 user: Ned Deily date: Mon Apr 18 11:29:56 2011 -0700 summary: Improve description of "svn-like" workflow. (Patch by Carl Meyer) files: patch.rst | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/patch.rst b/patch.rst --- a/patch.rst +++ b/patch.rst @@ -15,8 +15,8 @@ Mercurial allows for various workflows according to each person's or project's preference. We present here a very simple solution based on mq_ (*Mercurial Queues*). You are welcome to use any approach you like (including -a svn-like approach of simply never saving any changes you make to your working -copy and using ``hg diff`` to create a patch). Usage of mq_ is merely a +a svn-like approach of simply using ``hg diff`` to create a patch based on +uncommitted changes in your working copy). Usage of mq_ is merely a suggestion; it's a balance between being able to do everything needed while allowing for more powerful usage if desired in the future. -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Mon Apr 18 21:56:50 2011 From: python-checkins at python.org (r.david.murray) Date: Mon, 18 Apr 2011 21:56:50 +0200 Subject: [Python-checkins] cpython (3.2): Fix markup. Message-ID: http://hg.python.org/cpython/rev/a55c32f161dd changeset: 69429:a55c32f161dd branch: 3.2 parent: 69424:28ab8c6ad8f9 user: R David Murray date: Mon Apr 18 15:54:58 2011 -0400 summary: Fix markup. files: Doc/library/email.header.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/email.header.rst b/Doc/library/email.header.rst --- a/Doc/library/email.header.rst +++ b/Doc/library/email.header.rst @@ -119,7 +119,7 @@ which they appear in the string. Space and tab may be included in the string to indicate whether preference should be given to one over the other as a split point when other split chars do not appear in the line - being split. Splitchars does not affect RFC 2047 encoded lines. + being split. Splitchars does not affect :RFC:`2047` encoded lines. *maxlinelen*, if given, overrides the instance's value for the maximum line length. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 18 21:56:52 2011 From: python-checkins at python.org (r.david.murray) Date: Mon, 18 Apr 2011 21:56:52 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge: Fix markup. Message-ID: http://hg.python.org/cpython/rev/faabd0224d42 changeset: 69430:faabd0224d42 parent: 69428:2f3fda9d3906 parent: 69429:a55c32f161dd user: R David Murray date: Mon Apr 18 15:55:45 2011 -0400 summary: Merge: Fix markup. files: Doc/library/email.header.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/email.header.rst b/Doc/library/email.header.rst --- a/Doc/library/email.header.rst +++ b/Doc/library/email.header.rst @@ -119,7 +119,7 @@ which they appear in the string. Space and tab may be included in the string to indicate whether preference should be given to one over the other as a split point when other split chars do not appear in the line - being split. Splitchars does not affect RFC 2047 encoded lines. + being split. Splitchars does not affect :RFC:`2047` encoded lines. *maxlinelen*, if given, overrides the instance's value for the maximum line length. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 18 22:01:02 2011 From: python-checkins at python.org (r.david.murray) Date: Mon, 18 Apr 2011 22:01:02 +0200 Subject: [Python-checkins] cpython: Markup and text fixes from Georg Brandl's review. Message-ID: http://hg.python.org/cpython/rev/2127df2c972e changeset: 69431:2127df2c972e user: R David Murray date: Mon Apr 18 16:00:47 2011 -0400 summary: Markup and text fixes from Georg Brandl's review. files: Doc/library/email.parser.rst | 15 ++++-- Doc/library/email.policy.rst | 49 ++++++++++++----------- 2 files changed, 36 insertions(+), 28 deletions(-) diff --git a/Doc/library/email.parser.rst b/Doc/library/email.parser.rst --- a/Doc/library/email.parser.rst +++ b/Doc/library/email.parser.rst @@ -211,16 +211,19 @@ ``Parser().parsestr(s)``. *_class* and *policy* are interpreted as with the :class:`Parser` class constructor. - .. versionchanged:: removed *strict*, added *policy* + .. versionchanged:: 3.3 + Removed the *strict* argument. Added the *policy* keyword. -.. function:: message_from_bytes(s, _class=email.message.Message, strict=None) +.. function:: message_from_bytes(s, _class=email.message.Message, *, \ + policy=policy.default) Return a message object structure from a byte string. This is exactly equivalent to ``BytesParser().parsebytes(s)``. Optional *_class* and *strict* are interpreted as with the :class:`Parser` class constructor. .. versionadded:: 3.2 - .. versionchanged:: 3.3 removed *strict*, added *policy* + .. versionchanged:: 3.3 + Removed the *strict* argument. Added the *policy* keyword. .. function:: message_from_file(fp, _class=email.message.Message, *, \ policy=policy.default) @@ -229,7 +232,8 @@ This is exactly equivalent to ``Parser().parse(fp)``. *_class* and *policy* are interpreted as with the :class:`Parser` class constructor. - .. versionchanged:: 3.3 removed *strict*, added *policy* + .. versionchanged:: + Removed the *strict* argument. Added the *policy* keyword. .. function:: message_from_binary_file(fp, _class=email.message.Message, *, \ policy=policy.default) @@ -240,7 +244,8 @@ class constructor. .. versionadded:: 3.2 - .. versionchanged:: 3.3 removed *strict*, added *policy* + .. versionchanged:: 3.3 + Removed the *strict* argument. Added the *policy* keyword. Here's an example of how you might use this at an interactive Python prompt:: diff --git a/Doc/library/email.policy.rst b/Doc/library/email.policy.rst --- a/Doc/library/email.policy.rst +++ b/Doc/library/email.policy.rst @@ -4,6 +4,8 @@ .. module:: email.policy :synopsis: Controlling the parsing and generating of messages +.. versionadded: 3.3 + The :mod:`email` package's prime focus is the handling of email messages as described by the various email and MIME RFCs. However, the general format of @@ -14,8 +16,8 @@ not. And even when working with email, there are times when it is desirable to break strict compliance with the RFCs. -Policy objects are the mechanism used to provide the email package with the -flexibility to handle all these disparate use cases, +Policy objects give the email package the flexibility to handle all these +disparate use cases. A :class:`Policy` object encapsulates a set of attributes and methods that control the behavior of various components of the email package during use. @@ -39,24 +41,23 @@ can be different. As an example, the following code could be used to read an email message from a -file on disk and pass it to the system ``sendmail`` program on a ``unix`` -system:: +file on disk and pass it to the system ``sendmail`` program on a Unix system:: >>> from email import msg_from_binary_file >>> from email.generator import BytesGenerator >>> import email.policy >>> from subprocess import Popen, PIPE >>> with open('mymsg.txt', 'b') as f: - >>> msg = msg_from_binary_file(f, policy=email.policy.mbox) + ... Msg = msg_from_binary_file(f, policy=email.policy.mbox) >>> p = Popen(['sendmail', msg['To'][0].address], stdin=PIPE) - >>> g = BytesGenerator(p.stdin, email.policy.policy=SMTP) + >>> g = BytesGenerator(p.stdin, policy=email.policy.SMTP) >>> g.flatten(msg) >>> p.stdin.close() >>> rc = p.wait() Some email package methods accept a *policy* keyword argument, allowing the -policy to be overridden for that method. For example, the following code use -the :meth:`email.message.Message.as_string` method to the *msg* object from the +policy to be overridden for that method. For example, the following code uses +the :meth:`email.message.Message.as_string` method of the *msg* object from the previous example and re-write it to a file using the native line separators for the platform on which it is running:: @@ -106,19 +107,19 @@ .. attribute:: linesep The string to be used to terminate lines in serialized output. The - default is '\\n' because that's the internal end-of-line discipline used - by Python, though '\\r\\n' is required by the RFCs. See `Policy + default is ``\n`` because that's the internal end-of-line discipline used + by Python, though ``\r\n`` is required by the RFCs. See `Policy Instances`_ for policies that use an RFC conformant linesep. Setting it to :attr:`os.linesep` may also be useful. .. attribute:: must_be_7bit - If :const:`True`, data output by a bytes generator is limited to ASCII + If ``True``, data output by a bytes generator is limited to ASCII characters. If :const:`False` (the default), then bytes with the high bit set are preserved and/or allowed in certain contexts (for example, where possible a content transfer encoding of ``8bit`` will be used). - String generators act as if ``must_be_7bit`` is `True` regardless of the - policy in effect, since a string cannot represent non-ASCII bytes. + String generators act as if ``must_be_7bit`` is ``True`` regardless of + the policy in effect, since a string cannot represent non-ASCII bytes. .. attribute:: raise_on_defect @@ -126,6 +127,8 @@ :const:`False` (the default), defects will be passed to the :meth:`register_defect` method. + :mod:`Policy` object also have the following methods: + .. method:: handle_defect(obj, defect) *obj* is the object on which to register the defect. *defect* should be @@ -145,7 +148,7 @@ handling of defects. The default implementation calls the ``append`` method of the ``defects`` attribute of *obj*. - .. method:: clone(obj, *kw): + .. method:: clone(obj, *kw) Return a new :class:`Policy` instance whose attributes have the same values as the current instance, except where those attributes are @@ -153,27 +156,27 @@ Policy Instances -................ +^^^^^^^^^^^^^^^^ The following instances of :class:`Policy` provide defaults suitable for specific common application domains. .. data:: default - An instance of :class:`Policy` with all defaults unchanged. + An instance of :class:`Policy` with all defaults unchanged. .. data:: SMTP - Output serialized from a message will conform to the email and SMTP - RFCs. The only changed attribute is :attr:`linesep`, which is set to - ``\r\n``. + Output serialized from a message will conform to the email and SMTP + RFCs. The only changed attribute is :attr:`linesep`, which is set to + ``\r\n``. .. data:: HTTP - Suitable for use when serializing headers for use in HTTP traffic. - :attr:`linesep` is set to ``\r\n``, and :attr:`max_line_length` is set to - :const:`None` (unlimited). + Suitable for use when serializing headers for use in HTTP traffic. + :attr:`linesep` is set to ``\r\n``, and :attr:`max_line_length` is set to + :const:`None` (unlimited). .. data:: strict - :attr:`raise_on_defect` is set to :const:`True`. + :attr:`raise_on_defect` is set to :const:`True`. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 19 00:47:28 2011 From: python-checkins at python.org (philip.jenvey) Date: Tue, 19 Apr 2011 00:47:28 +0200 Subject: [Python-checkins] hooks: from address is really always built from to address Message-ID: http://hg.python.org/hooks/rev/f6d82c6d5a7e changeset: 70:f6d82c6d5a7e user: Philip Jenvey date: Sun Apr 17 23:25:15 2011 -0700 summary: from address is really always built from to address files: mail.py | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mail.py b/mail.py --- a/mail.py +++ b/mail.py @@ -16,7 +16,6 @@ BASE = 'http://hg.python.org/' CSET_URL = BASE + '%s/rev/%s' -FROM = '%s ' def send(sub, sender, to, body): msg = MIMEMultipart() @@ -75,6 +74,7 @@ if to is None: print 'no email address configured' return False + sender = '%s <%s>' % (user, to) prefixes = [path] @@ -105,7 +105,7 @@ subj = prefixes + desc - send(subj, FROM % user, to, '\n'.join(body) + '\n') + send(subj, sender, to, '\n'.join(body) + '\n') print 'notified %s of incoming changeset %s' % (to, ctx) return False -- Repository URL: http://hg.python.org/hooks From python-checkins at python.org Tue Apr 19 01:48:47 2011 From: python-checkins at python.org (philip.jenvey) Date: Tue, 19 Apr 2011 01:48:47 +0200 Subject: [Python-checkins] hooks: parameterize the allowed branches so the Jython repo can reuse this hook Message-ID: http://hg.python.org/hooks/rev/24eafedae830 changeset: 71:24eafedae830 user: Philip Jenvey date: Mon Apr 18 16:47:54 2011 -0700 summary: parameterize the allowed branches so the Jython repo can reuse this hook files: checkbranch.py | 10 +++++++++- 1 files changed, 9 insertions(+), 1 deletions(-) diff --git a/checkbranch.py b/checkbranch.py --- a/checkbranch.py +++ b/checkbranch.py @@ -7,6 +7,9 @@ [hooks] pretxnchangegroup.checkbranch = python:/home/hg/repos/hooks/checkbranch.py:hook + +[checkbranch] +allow-branches = default, 3.2, 3.1, 2.7, 2.6, 2.5 """ from mercurial.node import bin @@ -14,6 +17,11 @@ def hook(ui, repo, node, **kwargs): + branches = ui.configlist('checkbranch', 'allow-branches') + if not branches: + print 'checkbranch: No branches are configured' + return False + n = bin(node) start = repo.changelog.rev(n) end = len(repo.changelog) @@ -22,7 +30,7 @@ n = repo.changelog.node(rev) ctx = repo[n] branch = ctx.branch() - if branch not in ('default', '3.2', '3.1', '2.7', '2.6', '2.5'): + if branch not in branches: ui.warn(' - changeset %s on disallowed branch %r!\n' % (ctx, branch)) failed = True -- Repository URL: http://hg.python.org/hooks From python-checkins at python.org Tue Apr 19 02:29:16 2011 From: python-checkins at python.org (nadeem.vawda) Date: Tue, 19 Apr 2011 02:29:16 +0200 Subject: [Python-checkins] cpython (2.7): Fix sporadic failure in test_startfile. Message-ID: http://hg.python.org/cpython/rev/84272228d7db changeset: 69432:84272228d7db branch: 2.7 parent: 69427:ebd080593351 user: Nadeem Vawda date: Tue Apr 19 01:35:58 2011 +0200 summary: Fix sporadic failure in test_startfile. Wait for the child process to terminate before ending the test, so that the regrtest cleanup code doesn't get an error when it tries to delete the temporary CWD. files: Lib/test/test_startfile.py | 6 ++++++ Misc/NEWS | 2 ++ 2 files changed, 8 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_startfile.py b/Lib/test/test_startfile.py --- a/Lib/test/test_startfile.py +++ b/Lib/test/test_startfile.py @@ -11,6 +11,7 @@ from test import test_support import os from os import path +from time import sleep startfile = test_support.get_attribute(os, 'startfile') @@ -26,11 +27,16 @@ empty = path.join(path.dirname(__file__), "empty.vbs") startfile(empty) startfile(empty, "open") + # Give the child process some time to exit before we finish. + # Otherwise the cleanup code will not be able to delete the cwd, + # because it is still in use. + sleep(0.1) def test_empty_u(self): empty = path.join(path.dirname(__file__), "empty.vbs") startfile(unicode(empty, "mbcs")) startfile(unicode(empty, "mbcs"), "open") + sleep(0.1) def test_main(): test_support.run_unittest(TestCase) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -367,6 +367,8 @@ Tests ----- +- Fix test_startfile to wait for child process to terminate before finishing. + - Issue #11719: Fix message about unexpected test_msilib skip on non-Windows platforms. Patch by Nadeem Vawda. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 19 02:29:18 2011 From: python-checkins at python.org (nadeem.vawda) Date: Tue, 19 Apr 2011 02:29:18 +0200 Subject: [Python-checkins] cpython (3.1): Fix sporadic failure in test_startfile. Message-ID: http://hg.python.org/cpython/rev/8b7b3748f876 changeset: 69433:8b7b3748f876 branch: 3.1 parent: 69423:319f7af9ee5e user: Nadeem Vawda date: Tue Apr 19 01:38:47 2011 +0200 summary: Fix sporadic failure in test_startfile. Wait for the child process to terminate before ending the test, so that the regrtest cleanup code doesn't get an error when it tries to delete the temporary CWD. files: Lib/test/test_startfile.py | 5 +++++ Misc/NEWS | 2 ++ 2 files changed, 7 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_startfile.py b/Lib/test/test_startfile.py --- a/Lib/test/test_startfile.py +++ b/Lib/test/test_startfile.py @@ -11,6 +11,7 @@ from test import support import os from os import path +from time import sleep startfile = support.get_attribute(os, 'startfile') @@ -23,6 +24,10 @@ empty = path.join(path.dirname(__file__), "empty.vbs") startfile(empty) startfile(empty, "open") + # Give the child process some time to exit before we finish. + # Otherwise the cleanup code will not be able to delete the cwd, + # because it is still in use. + sleep(0.1) def test_main(): support.run_unittest(TestCase) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -315,6 +315,8 @@ Tests ----- +- Fix test_startfile to wait for child process to terminate before finishing. + - Issue #11719: Fix message about unexpected test_msilib skip on non-Windows platforms. Patch by Nadeem Vawda. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 19 02:29:19 2011 From: python-checkins at python.org (nadeem.vawda) Date: Tue, 19 Apr 2011 02:29:19 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): Merge test_startfile fix from 3.1. Message-ID: http://hg.python.org/cpython/rev/8abab11fcb29 changeset: 69434:8abab11fcb29 branch: 3.2 parent: 69429:a55c32f161dd parent: 69433:8b7b3748f876 user: Nadeem Vawda date: Tue Apr 19 01:40:45 2011 +0200 summary: Merge test_startfile fix from 3.1. files: Lib/test/test_startfile.py | 5 +++++ Misc/NEWS | 2 ++ 2 files changed, 7 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_startfile.py b/Lib/test/test_startfile.py --- a/Lib/test/test_startfile.py +++ b/Lib/test/test_startfile.py @@ -11,6 +11,7 @@ from test import support import os from os import path +from time import sleep startfile = support.get_attribute(os, 'startfile') @@ -23,6 +24,10 @@ empty = path.join(path.dirname(__file__), "empty.vbs") startfile(empty) startfile(empty, "open") + # Give the child process some time to exit before we finish. + # Otherwise the cleanup code will not be able to delete the cwd, + # because it is still in use. + sleep(0.1) def test_main(): support.run_unittest(TestCase) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -751,6 +751,8 @@ Tests ----- +- Fix test_startfile to wait for child process to terminate before finishing. + - Issue #10822: Fix test_posix:test_getgroups failure under Solaris. Patch by Ross Lagerwall. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 19 02:29:23 2011 From: python-checkins at python.org (nadeem.vawda) Date: Tue, 19 Apr 2011 02:29:23 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge test_startfile fix from 3.2. Message-ID: http://hg.python.org/cpython/rev/660a3345afa2 changeset: 69435:660a3345afa2 parent: 69431:2127df2c972e parent: 69434:8abab11fcb29 user: Nadeem Vawda date: Tue Apr 19 01:41:28 2011 +0200 summary: Merge test_startfile fix from 3.2. files: Lib/test/test_startfile.py | 5 +++++ Misc/NEWS | 2 ++ 2 files changed, 7 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_startfile.py b/Lib/test/test_startfile.py --- a/Lib/test/test_startfile.py +++ b/Lib/test/test_startfile.py @@ -11,6 +11,7 @@ from test import support import os from os import path +from time import sleep startfile = support.get_attribute(os, 'startfile') @@ -23,6 +24,10 @@ empty = path.join(path.dirname(__file__), "empty.vbs") startfile(empty) startfile(empty, "open") + # Give the child process some time to exit before we finish. + # Otherwise the cleanup code will not be able to delete the cwd, + # because it is still in use. + sleep(0.1) def test_main(): support.run_unittest(TestCase) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -985,6 +985,8 @@ Tests ----- +- Fix test_startfile to wait for child process to terminate before finishing. + - Issue #10822: Fix test_posix:test_getgroups failure under Solaris. Patch by Ross Lagerwall. -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Tue Apr 19 05:00:20 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Tue, 19 Apr 2011 05:00:20 +0200 Subject: [Python-checkins] Daily reference leaks (660a3345afa2): sum=-323 Message-ID: results for 660a3345afa2 on branch "default" -------------------------------------------- test_pyexpat leaked [-56, -267, 0] references, sum=-323 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogcS6Eht', '-x'] From python-checkins at python.org Tue Apr 19 09:21:23 2011 From: python-checkins at python.org (georg.brandl) Date: Tue, 19 Apr 2011 09:21:23 +0200 Subject: [Python-checkins] cpython: Add new email.policy document to the toctree and fix markup glitch. Message-ID: http://hg.python.org/cpython/rev/6afce92ffaef changeset: 69436:6afce92ffaef user: Georg Brandl date: Tue Apr 19 09:21:00 2011 +0200 summary: Add new email.policy document to the toctree and fix markup glitch. files: Doc/library/email.policy.rst | 2 +- Doc/library/email.rst | 1 + 2 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Doc/library/email.policy.rst b/Doc/library/email.policy.rst --- a/Doc/library/email.policy.rst +++ b/Doc/library/email.policy.rst @@ -27,7 +27,7 @@ pre-created :class:`Policy` instances. In addition to a :const:`default` instance, there are instances tailored for certain applications. For example there is an :const:`SMTP` :class:`Policy` with defaults appropriate for -generating output to be sent to an SMTP server. These are listed :ref:`below +generating output to be sent to an SMTP server. These are listed `below `. In general an application will only need to deal with setting the policy at the diff --git a/Doc/library/email.rst b/Doc/library/email.rst --- a/Doc/library/email.rst +++ b/Doc/library/email.rst @@ -51,6 +51,7 @@ email.message.rst email.parser.rst email.generator.rst + email.policy.rst email.mime.rst email.header.rst email.charset.rst -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 19 09:47:21 2011 From: python-checkins at python.org (giampaolo.rodola) Date: Tue, 19 Apr 2011 09:47:21 +0200 Subject: [Python-checkins] cpython: os.sendfile(): on Linux if offset parameter is passed as NULL we were Message-ID: http://hg.python.org/cpython/rev/8c49f7fbba1d changeset: 69437:8c49f7fbba1d user: Giampaolo Rodola' date: Tue Apr 19 09:47:16 2011 +0200 summary: os.sendfile(): on Linux if offset parameter is passed as NULL we were erroneously returning a (bytes_sent, None) tuple instead of bytes_sent files: Modules/posixmodule.c | 5 ++--- 1 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -6450,8 +6450,7 @@ Py_END_ALLOW_THREADS if (ret < 0) return posix_error(); - Py_INCREF(Py_None); - return Py_BuildValue("nO", ret, Py_None); + return Py_BuildValue("n", ret); } #endif if (!_parse_off_t(offobj, &offset)) @@ -8730,7 +8729,7 @@ long uid, gid; int flags = 0; char *path; - + if (!PyArg_ParseTuple(args, "iO&ll|i:fchownat", &dirfd, PyUnicode_FSConverter, &opath, &uid, &gid, &flags)) return NULL; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 19 14:59:00 2011 From: python-checkins at python.org (vinay.sajip) Date: Tue, 19 Apr 2011 14:59:00 +0200 Subject: [Python-checkins] cpython (2.7): Updated documentation on fileConfig(). Message-ID: http://hg.python.org/cpython/rev/18d29c790bd0 changeset: 69438:18d29c790bd0 branch: 2.7 parent: 69432:84272228d7db user: Vinay Sajip date: Tue Apr 19 13:47:23 2011 +0100 summary: Updated documentation on fileConfig(). files: Doc/library/logging.config.rst | 26 ++++++++++++++++----- 1 files changed, 20 insertions(+), 6 deletions(-) diff --git a/Doc/library/logging.config.rst b/Doc/library/logging.config.rst --- a/Doc/library/logging.config.rst +++ b/Doc/library/logging.config.rst @@ -74,15 +74,29 @@ .. versionadded:: 2.7 -.. function:: fileConfig(fname[, defaults]) +.. function:: fileConfig(fname, defaults=None, disable_existing_loggers=True) - Reads the logging configuration from a :mod:`configparser`\-format file named - *fname*. This function can be called several times from an application, - allowing an end user to select from various pre-canned + Reads the logging configuration from a :mod:`configparser`\-format file + named *fname*. This function can be called several times from an + application, allowing an end user to select from various pre-canned configurations (if the developer provides a mechanism to present the choices - and load the chosen configuration). Defaults to be passed to the ConfigParser - can be specified in the *defaults* argument. + and load the chosen configuration). + :param defaults: Defaults to be passed to the ConfigParser can be specified + in this argument. + + :param disable_existing_loggers: If specified as ``False``, loggers which + exist when this call is made are left + alone. The default is ``True`` because this + enables old behaviour in a backward- + compatible way. This behaviour is to + disable any existing loggers unless they or + their ancestors are explicitly named in the + logging configuration. + + .. versionchanged:: 2.6 + The ``disable_existing_loggers`` keyword argument was added. Previously, + existing loggers were *always* disabled. .. function:: listen(port=DEFAULT_LOGGING_CONFIG_PORT) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 19 14:59:01 2011 From: python-checkins at python.org (vinay.sajip) Date: Tue, 19 Apr 2011 14:59:01 +0200 Subject: [Python-checkins] cpython (3.2): Updated documentation on fileConfig(). Message-ID: http://hg.python.org/cpython/rev/d4bc42400692 changeset: 69439:d4bc42400692 branch: 3.2 parent: 69434:8abab11fcb29 user: Vinay Sajip date: Tue Apr 19 13:56:39 2011 +0100 summary: Updated documentation on fileConfig(). files: Doc/library/logging.config.rst | 23 ++++++++++++++++----- 1 files changed, 17 insertions(+), 6 deletions(-) diff --git a/Doc/library/logging.config.rst b/Doc/library/logging.config.rst --- a/Doc/library/logging.config.rst +++ b/Doc/library/logging.config.rst @@ -74,14 +74,25 @@ .. versionadded:: 3.2 -.. function:: fileConfig(fname[, defaults]) +.. function:: fileConfig(fname, defaults=None, disable_existing_loggers=True) - Reads the logging configuration from a :mod:`configparser`\-format file named - *fname*. This function can be called several times from an application, - allowing an end user to select from various pre-canned + Reads the logging configuration from a :mod:`configparser`\-format file + named *fname*. This function can be called several times from an + application, allowing an end user to select from various pre-canned configurations (if the developer provides a mechanism to present the choices - and load the chosen configuration). Defaults to be passed to the ConfigParser - can be specified in the *defaults* argument. + and load the chosen configuration). + + :param defaults: Defaults to be passed to the ConfigParser can be specified + in this argument. + + :param disable_existing_loggers: If specified as ``False``, loggers which + exist when this call is made are left + alone. The default is ``True`` because this + enables old behaviour in a backward- + compatible way. This behaviour is to + disable any existing loggers unless they or + their ancestors are explicitly named in the + logging configuration. .. function:: listen(port=DEFAULT_LOGGING_CONFIG_PORT) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 19 14:59:04 2011 From: python-checkins at python.org (vinay.sajip) Date: Tue, 19 Apr 2011 14:59:04 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merged documentation fix from 3.2. Message-ID: http://hg.python.org/cpython/rev/253f8623ea0b changeset: 69440:253f8623ea0b parent: 69437:8c49f7fbba1d parent: 69439:d4bc42400692 user: Vinay Sajip date: Tue Apr 19 13:58:49 2011 +0100 summary: Merged documentation fix from 3.2. files: Doc/library/logging.config.rst | 23 ++++++++++++++++----- 1 files changed, 17 insertions(+), 6 deletions(-) diff --git a/Doc/library/logging.config.rst b/Doc/library/logging.config.rst --- a/Doc/library/logging.config.rst +++ b/Doc/library/logging.config.rst @@ -74,14 +74,25 @@ .. versionadded:: 3.2 -.. function:: fileConfig(fname[, defaults]) +.. function:: fileConfig(fname, defaults=None, disable_existing_loggers=True) - Reads the logging configuration from a :mod:`configparser`\-format file named - *fname*. This function can be called several times from an application, - allowing an end user to select from various pre-canned + Reads the logging configuration from a :mod:`configparser`\-format file + named *fname*. This function can be called several times from an + application, allowing an end user to select from various pre-canned configurations (if the developer provides a mechanism to present the choices - and load the chosen configuration). Defaults to be passed to the ConfigParser - can be specified in the *defaults* argument. + and load the chosen configuration). + + :param defaults: Defaults to be passed to the ConfigParser can be specified + in this argument. + + :param disable_existing_loggers: If specified as ``False``, loggers which + exist when this call is made are left + alone. The default is ``True`` because this + enables old behaviour in a backward- + compatible way. This behaviour is to + disable any existing loggers unless they or + their ancestors are explicitly named in the + logging configuration. .. function:: listen(port=DEFAULT_LOGGING_CONFIG_PORT) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 19 18:54:59 2011 From: python-checkins at python.org (raymond.hettinger) Date: Tue, 19 Apr 2011 18:54:59 +0200 Subject: [Python-checkins] cpython (2.7): Issue 11875: Keep OrderedDict's __reduce__ from temporarily mutating the object. Message-ID: http://hg.python.org/cpython/rev/3150b6939731 changeset: 69441:3150b6939731 branch: 2.7 parent: 69438:18d29c790bd0 user: Raymond Hettinger date: Tue Apr 19 09:48:39 2011 -0700 summary: Issue 11875: Keep OrderedDict's __reduce__ from temporarily mutating the object. files: Lib/collections.py | 5 ++--- Misc/NEWS | 3 +++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Lib/collections.py b/Lib/collections.py --- a/Lib/collections.py +++ b/Lib/collections.py @@ -115,10 +115,9 @@ def __reduce__(self): 'Return state information for pickling' items = [[k, self[k]] for k in self] - tmp = self.__map, self.__root - del self.__map, self.__root inst_dict = vars(self).copy() - self.__map, self.__root = tmp + for k in vars(OrderedDict()): + inst_dict.pop(k, None) if inst_dict: return (self.__class__, (items,), inst_dict) return self.__class__, (items,) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -59,6 +59,9 @@ Py_AddPendingCall() for the first signal to fix a deadlock on reentrant or parallel calls. PyErr_SetInterrupt() writes also into the wake up file. +- Issue #11875: collections.OrderedDict's __reduce__ was temporarily + mutating the object instead of just working on a copy. + - Issue #11442: Add a charset parameter to the Content-type in SimpleHTTPServer to avoid XSS attacks. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 19 18:55:00 2011 From: python-checkins at python.org (raymond.hettinger) Date: Tue, 19 Apr 2011 18:55:00 +0200 Subject: [Python-checkins] cpython (2.7): Use a generic class lookup. Message-ID: http://hg.python.org/cpython/rev/f3088be1b20d changeset: 69442:f3088be1b20d branch: 2.7 user: Raymond Hettinger date: Tue Apr 19 09:52:21 2011 -0700 summary: Use a generic class lookup. files: Lib/collections.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/collections.py b/Lib/collections.py --- a/Lib/collections.py +++ b/Lib/collections.py @@ -116,7 +116,7 @@ 'Return state information for pickling' items = [[k, self[k]] for k in self] inst_dict = vars(self).copy() - for k in vars(OrderedDict()): + for k in vars(self.__class__()): inst_dict.pop(k, None) if inst_dict: return (self.__class__, (items,), inst_dict) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 19 20:15:34 2011 From: python-checkins at python.org (raymond.hettinger) Date: Tue, 19 Apr 2011 20:15:34 +0200 Subject: [Python-checkins] cpython (3.1): Issue 11875: Keep OrderedDict's __reduce__ from temporarily mutating the object. Message-ID: http://hg.python.org/cpython/rev/50a89739836f changeset: 69443:50a89739836f branch: 3.1 parent: 69412:49e756c8c08b user: Raymond Hettinger date: Tue Apr 19 10:05:03 2011 -0700 summary: Issue 11875: Keep OrderedDict's __reduce__ from temporarily mutating the object. files: Lib/collections.py | 5 ++--- Misc/NEWS | 3 +++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Lib/collections.py b/Lib/collections.py --- a/Lib/collections.py +++ b/Lib/collections.py @@ -101,10 +101,9 @@ def __reduce__(self): 'Return state information for pickling' items = [[k, self[k]] for k in self] - tmp = self.__map, self.__root, self.__in_repr - del self.__map, self.__root, self.__in_repr inst_dict = vars(self).copy() - self.__map, self.__root, self.__in_repr = tmp + for k in vars(self.__class__()): + inst_dict.pop(k, None) if inst_dict: return (self.__class__, (items,), inst_dict) return self.__class__, (items,) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -58,6 +58,9 @@ - Issue #11467: Fix urlparse behavior when handling urls which contains scheme specific part only digits. Patch by Santoso Wijaya. +- Issue #11875: collections.OrderedDict's __reduce__ was temporarily + mutating the object instead of just working on a copy. + - collections.Counter().copy() now works correctly for subclasses. - Issue #11474: Fix the bug with url2pathname() handling of '/C|/' on Windows. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 19 20:15:35 2011 From: python-checkins at python.org (raymond.hettinger) Date: Tue, 19 Apr 2011 20:15:35 +0200 Subject: [Python-checkins] cpython (3.1): Hmm, __ne__ was missing Message-ID: http://hg.python.org/cpython/rev/15afaf8aa155 changeset: 69444:15afaf8aa155 branch: 3.1 user: Raymond Hettinger date: Tue Apr 19 10:05:53 2011 -0700 summary: Hmm, __ne__ was missing files: Lib/collections.py | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Lib/collections.py b/Lib/collections.py --- a/Lib/collections.py +++ b/Lib/collections.py @@ -112,6 +112,7 @@ keys = MutableMapping.keys values = MutableMapping.values items = MutableMapping.items + __ne__ = MutableMapping.__ne__ __marker = object() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 19 20:15:36 2011 From: python-checkins at python.org (raymond.hettinger) Date: Tue, 19 Apr 2011 20:15:36 +0200 Subject: [Python-checkins] cpython (3.2): Issue 11875: Keep OrderedDict's __reduce__ from temporarily mutating the object. Message-ID: http://hg.python.org/cpython/rev/a7ac7a7c8c78 changeset: 69445:a7ac7a7c8c78 branch: 3.2 parent: 69413:76fb918f98dd user: Raymond Hettinger date: Tue Apr 19 10:21:27 2011 -0700 summary: Issue 11875: Keep OrderedDict's __reduce__ from temporarily mutating the object. files: Lib/collections.py | 5 ++--- Misc/NEWS | 3 +++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Lib/collections.py b/Lib/collections.py --- a/Lib/collections.py +++ b/Lib/collections.py @@ -154,10 +154,9 @@ def __reduce__(self): 'Return state information for pickling' items = [[k, self[k]] for k in self] - tmp = self.__map, self.__root, self.__hardroot - del self.__map, self.__root, self.__hardroot inst_dict = vars(self).copy() - self.__map, self.__root, self.__hardroot = tmp + for k in vars(self.__class__()): + inst_dict.pop(k, None) if inst_dict: return (self.__class__, (items,), inst_dict) return self.__class__, (items,) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -62,6 +62,9 @@ - Issue #11852: Add missing imports and update tests. +- Issue #11875: collections.OrderedDict's __reduce__ was temporarily + mutating the object instead of just working on a copy. + - Issue #11467: Fix urlparse behavior when handling urls which contains scheme specific part only digits. Patch by Santoso Wijaya. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 19 20:15:39 2011 From: python-checkins at python.org (raymond.hettinger) Date: Tue, 19 Apr 2011 20:15:39 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): merge Message-ID: http://hg.python.org/cpython/rev/87440bf1994f changeset: 69446:87440bf1994f branch: 3.2 parent: 69445:a7ac7a7c8c78 parent: 69444:15afaf8aa155 user: Raymond Hettinger date: Tue Apr 19 10:23:04 2011 -0700 summary: merge files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 19 20:15:45 2011 From: python-checkins at python.org (raymond.hettinger) Date: Tue, 19 Apr 2011 20:15:45 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Issue 11875: Keep OrderedDict's __reduce__ from temporarily mutating the object. Message-ID: http://hg.python.org/cpython/rev/928f17923b0d changeset: 69447:928f17923b0d parent: 69440:253f8623ea0b parent: 69446:87440bf1994f user: Raymond Hettinger date: Tue Apr 19 11:04:44 2011 -0700 summary: Issue 11875: Keep OrderedDict's __reduce__ from temporarily mutating the object. files: Lib/collections/__init__.py | 5 ++--- Misc/NEWS | 3 +++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Lib/collections/__init__.py b/Lib/collections/__init__.py --- a/Lib/collections/__init__.py +++ b/Lib/collections/__init__.py @@ -155,10 +155,9 @@ def __reduce__(self): 'Return state information for pickling' items = [[k, self[k]] for k in self] - tmp = self.__map, self.__root, self.__hardroot - del self.__map, self.__root, self.__hardroot inst_dict = vars(self).copy() - self.__map, self.__root, self.__hardroot = tmp + for k in vars(self.__class__()): + inst_dict.pop(k, None) if inst_dict: return (self.__class__, (items,), inst_dict) return self.__class__, (items,) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -121,6 +121,9 @@ - Issue #11852: Add missing imports and update tests. +- Issue #11875: collections.OrderedDict's __reduce__ was temporarily + mutating the object instead of just working on a copy. + - Issue #11467: Fix urlparse behavior when handling urls which contains scheme specific part only digits. Patch by Santoso Wijaya. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 19 20:15:46 2011 From: python-checkins at python.org (raymond.hettinger) Date: Tue, 19 Apr 2011 20:15:46 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> 3.2): Issue 11875: Keep OrderedDict's __reduce__ from temporarily mutating the object. Message-ID: http://hg.python.org/cpython/rev/937385024601 changeset: 69448:937385024601 branch: 3.2 parent: 69439:d4bc42400692 parent: 69446:87440bf1994f user: Raymond Hettinger date: Tue Apr 19 11:10:43 2011 -0700 summary: Issue 11875: Keep OrderedDict's __reduce__ from temporarily mutating the object. files: Lib/collections.py | 5 ++--- Misc/NEWS | 3 +++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Lib/collections.py b/Lib/collections.py --- a/Lib/collections.py +++ b/Lib/collections.py @@ -154,10 +154,9 @@ def __reduce__(self): 'Return state information for pickling' items = [[k, self[k]] for k in self] - tmp = self.__map, self.__root, self.__hardroot - del self.__map, self.__root, self.__hardroot inst_dict = vars(self).copy() - self.__map, self.__root, self.__hardroot = tmp + for k in vars(self.__class__()): + inst_dict.pop(k, None) if inst_dict: return (self.__class__, (items,), inst_dict) return self.__class__, (items,) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -68,6 +68,9 @@ - Issue #11852: Add missing imports and update tests. +- Issue #11875: collections.OrderedDict's __reduce__ was temporarily + mutating the object instead of just working on a copy. + - Issue #11467: Fix urlparse behavior when handling urls which contains scheme specific part only digits. Patch by Santoso Wijaya. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 19 20:15:47 2011 From: python-checkins at python.org (raymond.hettinger) Date: Tue, 19 Apr 2011 20:15:47 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): merge Message-ID: http://hg.python.org/cpython/rev/382ddc1d94e0 changeset: 69449:382ddc1d94e0 parent: 69447:928f17923b0d parent: 69448:937385024601 user: Raymond Hettinger date: Tue Apr 19 11:11:20 2011 -0700 summary: merge files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 19 20:15:48 2011 From: python-checkins at python.org (raymond.hettinger) Date: Tue, 19 Apr 2011 20:15:48 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.1): merge Message-ID: http://hg.python.org/cpython/rev/240e964fbd42 changeset: 69450:240e964fbd42 branch: 3.1 parent: 69444:15afaf8aa155 parent: 69433:8b7b3748f876 user: Raymond Hettinger date: Tue Apr 19 11:12:47 2011 -0700 summary: merge files: Doc/c-api/init.rst | 2 +- Lib/test/test_startfile.py | 5 +++++ Misc/NEWS | 6 ++++++ Modules/signalmodule.c | 26 ++++++++++++++++---------- 4 files changed, 28 insertions(+), 11 deletions(-) diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -892,7 +892,7 @@ main thread where it has possession of the global interpreter lock and can perform any Python API calls. -.. cfunction:: void Py_AddPendingCall( int (*func)(void *, void *arg) ) +.. cfunction:: void Py_AddPendingCall(int (*func)(void *), void *arg) .. index:: single: Py_AddPendingCall() diff --git a/Lib/test/test_startfile.py b/Lib/test/test_startfile.py --- a/Lib/test/test_startfile.py +++ b/Lib/test/test_startfile.py @@ -11,6 +11,7 @@ from test import support import os from os import path +from time import sleep startfile = support.get_attribute(os, 'startfile') @@ -23,6 +24,10 @@ empty = path.join(path.dirname(__file__), "empty.vbs") startfile(empty) startfile(empty, "open") + # Give the child process some time to exit before we finish. + # Otherwise the cleanup code will not be able to delete the cwd, + # because it is still in use. + sleep(0.1) def test_main(): support.run_unittest(TestCase) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -55,6 +55,10 @@ Library ------- +- Issue #11768: The signal handler of the signal module only calls + Py_AddPendingCall() for the first signal to fix a deadlock on reentrant or + parallel calls. PyErr_SetInterrupt() writes also into the wake up file. + - Issue #11467: Fix urlparse behavior when handling urls which contains scheme specific part only digits. Patch by Santoso Wijaya. @@ -314,6 +318,8 @@ Tests ----- +- Fix test_startfile to wait for child process to terminate before finishing. + - Issue #11719: Fix message about unexpected test_msilib skip on non-Windows platforms. Patch by Nadeem Vawda. diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c --- a/Modules/signalmodule.c +++ b/Modules/signalmodule.c @@ -164,6 +164,20 @@ } static void +trip_signal(int sig_num) +{ + Handlers[sig_num].tripped = 1; + if (is_tripped) + return; + /* Set is_tripped after setting .tripped, as it gets + cleared in PyErr_CheckSignals() before .tripped. */ + is_tripped = 1; + Py_AddPendingCall(checksignals_witharg, NULL); + if (wakeup_fd != -1) + write(wakeup_fd, "\0", 1); +} + +static void signal_handler(int sig_num) { int save_errno = errno; @@ -180,13 +194,7 @@ if (getpid() == main_pid) #endif { - Handlers[sig_num].tripped = 1; - /* Set is_tripped after setting .tripped, as it gets - cleared in PyErr_CheckSignals() before .tripped. */ - is_tripped = 1; - Py_AddPendingCall(checksignals_witharg, NULL); - if (wakeup_fd != -1) - write(wakeup_fd, "\0", 1); + trip_signal(sig_num); } #ifndef HAVE_SIGACTION @@ -932,9 +940,7 @@ void PyErr_SetInterrupt(void) { - is_tripped = 1; - Handlers[SIGINT].tripped = 1; - Py_AddPendingCall((int (*)(void *))PyErr_CheckSignals, NULL); + trip_signal(SIGINT); } void -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 19 20:15:49 2011 From: python-checkins at python.org (raymond.hettinger) Date: Tue, 19 Apr 2011 20:15:49 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> default): merge Message-ID: http://hg.python.org/cpython/rev/5b253226cd36 changeset: 69451:5b253226cd36 parent: 69449:382ddc1d94e0 parent: 69450:240e964fbd42 user: Raymond Hettinger date: Tue Apr 19 11:15:11 2011 -0700 summary: merge files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 19 22:24:49 2011 From: python-checkins at python.org (ezio.melotti) Date: Tue, 19 Apr 2011 22:24:49 +0200 Subject: [Python-checkins] cpython (2.7): Fix wrong number of functions noticed by Sandro Tosi. Message-ID: http://hg.python.org/cpython/rev/08b5e2c9112c changeset: 69452:08b5e2c9112c branch: 2.7 parent: 69442:f3088be1b20d user: Ezio Melotti date: Tue Apr 19 23:12:37 2011 +0300 summary: Fix wrong number of functions noticed by Sandro Tosi. files: Doc/library/subprocess.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst --- a/Doc/library/subprocess.rst +++ b/Doc/library/subprocess.rst @@ -200,7 +200,7 @@ Convenience Functions ^^^^^^^^^^^^^^^^^^^^^ -This module also defines two shortcut functions: +This module also defines the following shortcut functions: .. function:: call(*popenargs, **kwargs) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 19 22:24:50 2011 From: python-checkins at python.org (ezio.melotti) Date: Tue, 19 Apr 2011 22:24:50 +0200 Subject: [Python-checkins] cpython (3.1): Fix wrong number of functions noticed by Sandro Tosi. Message-ID: http://hg.python.org/cpython/rev/fb261fa85429 changeset: 69453:fb261fa85429 branch: 3.1 parent: 69450:240e964fbd42 user: Ezio Melotti date: Tue Apr 19 23:15:13 2011 +0300 summary: Fix wrong number of functions noticed by Sandro Tosi. files: Doc/library/subprocess.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst --- a/Doc/library/subprocess.rst +++ b/Doc/library/subprocess.rst @@ -193,7 +193,7 @@ Convenience Functions ^^^^^^^^^^^^^^^^^^^^^ -This module also defines four shortcut functions: +This module also defines the following shortcut functions: .. function:: call(*popenargs, **kwargs) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 19 22:24:52 2011 From: python-checkins at python.org (ezio.melotti) Date: Tue, 19 Apr 2011 22:24:52 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): Merge with 3.1. Message-ID: http://hg.python.org/cpython/rev/9179bd4037ad changeset: 69454:9179bd4037ad branch: 3.2 parent: 69448:937385024601 parent: 69453:fb261fa85429 user: Ezio Melotti date: Tue Apr 19 23:23:47 2011 +0300 summary: Merge with 3.1. files: Doc/library/subprocess.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst --- a/Doc/library/subprocess.rst +++ b/Doc/library/subprocess.rst @@ -244,7 +244,7 @@ Convenience Functions ^^^^^^^^^^^^^^^^^^^^^ -This module also defines four shortcut functions: +This module also defines the following shortcut functions: .. function:: call(*popenargs, **kwargs) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 19 22:24:54 2011 From: python-checkins at python.org (ezio.melotti) Date: Tue, 19 Apr 2011 22:24:54 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge with 3.2. Message-ID: http://hg.python.org/cpython/rev/c1b29ce313e0 changeset: 69455:c1b29ce313e0 parent: 69451:5b253226cd36 parent: 69454:9179bd4037ad user: Ezio Melotti date: Tue Apr 19 23:24:32 2011 +0300 summary: Merge with 3.2. files: Doc/library/subprocess.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst --- a/Doc/library/subprocess.rst +++ b/Doc/library/subprocess.rst @@ -255,7 +255,7 @@ Convenience Functions ^^^^^^^^^^^^^^^^^^^^^ -This module also defines four shortcut functions: +This module also defines the following shortcut functions: .. function:: call(*popenargs, timeout=None, **kwargs) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 19 23:36:22 2011 From: python-checkins at python.org (victor.stinner) Date: Tue, 19 Apr 2011 23:36:22 +0200 Subject: [Python-checkins] cpython: faulthandler: don't use sigprocmask() Message-ID: http://hg.python.org/cpython/rev/73ccc552fef3 changeset: 69456:73ccc552fef3 user: Victor Stinner date: Tue Apr 19 23:30:57 2011 +0200 summary: faulthandler: don't use sigprocmask() It has an undefined behaviour with threads, only use pthread_sigmask() if it is available (and not broken). files: Modules/faulthandler.c | 6 +----- 1 files changed, 1 insertions(+), 5 deletions(-) diff --git a/Modules/faulthandler.c b/Modules/faulthandler.c --- a/Modules/faulthandler.c +++ b/Modules/faulthandler.c @@ -418,16 +418,12 @@ const char* errmsg; PyThreadState *current; int ok; -#ifdef HAVE_PTHREAD_H +#if defined(HAVE_PTHREAD_SIGMASK) && !defined(HAVE_BROKEN_PTHREAD_SIGMASK) sigset_t set; /* we don't want to receive any signal */ sigfillset(&set); -#if defined(HAVE_PTHREAD_SIGMASK) && !defined(HAVE_BROKEN_PTHREAD_SIGMASK) pthread_sigmask(SIG_SETMASK, &set, NULL); -#else - sigprocmask(SIG_SETMASK, &set, NULL); -#endif #endif do { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 19 23:59:26 2011 From: python-checkins at python.org (victor.stinner) Date: Tue, 19 Apr 2011 23:59:26 +0200 Subject: [Python-checkins] cpython: Issue #11223: Add threading._info() function providing informations about the Message-ID: http://hg.python.org/cpython/rev/383a7301616b changeset: 69457:383a7301616b user: Victor Stinner date: Tue Apr 19 23:58:51 2011 +0200 summary: Issue #11223: Add threading._info() function providing informations about the thread implementation. Skip test_lock_acquire_interruption() and test_rlock_acquire_interruption() of test_threadsignals if a thread lock is implemented using a POSIX mutex and a POSIX condition variable. A POSIX condition variable cannot be interrupted by a signal (e.g. on Linux, the futex system call is restarted). files: Doc/library/threading.rst | 24 +++++++++ Doc/whatsnew/3.3.rst | 8 +++ Include/pythread.h | 4 +- Lib/test/test_os.py | 15 +++-- Lib/test/test_threading.py | 13 ++++- Lib/test/test_threadsignals.py | 7 ++ Lib/threading.py | 3 +- Misc/NEWS | 13 ++++- Modules/_threadmodule.c | 24 ++++++-- Python/thread.c | 57 ++++++++++++++++++++++ 10 files changed, 150 insertions(+), 18 deletions(-) diff --git a/Doc/library/threading.rst b/Doc/library/threading.rst --- a/Doc/library/threading.rst +++ b/Doc/library/threading.rst @@ -175,6 +175,30 @@ Availability: Windows, systems with POSIX threads. +.. function:: _info() + + Return a dictionary with informations about the thread implementation. + The ``'name'`` key gives the name of the thread implementation (string): + + * ``'nt'``: Windows threads + * ``'os2'``: OS/2 threads + * ``'pthread'``: POSIX threads + * ``'solaris'``: Solaris threads + + POSIX threads have two more keys: + + * ``'lock_implementation'`` (string): name of the lock + implementation + + * ``'semaphore'``: a lock uses a semaphore + * ``'mutex+cond'``: a lock uses a mutex and a condition variable + + * ``'pthread_version'`` (string, optional): name and version of the pthread + library + + .. versionadded:: 3.3 + + This module also defines the following constant: .. data:: TIMEOUT_MAX 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 @@ -112,6 +112,14 @@ (Contributed by Giampaolo Rodol? in :issue:`9795`) +threading +--------- + +* The :mod:`threading` module has a new :func:`~threading._info` function which + provides informations about the thread implementation. + + (:issue:`11223`) + Optimizations ============= diff --git a/Include/pythread.h b/Include/pythread.h --- a/Include/pythread.h +++ b/Include/pythread.h @@ -32,7 +32,7 @@ on a lock (see PyThread_acquire_lock_timed() below). PY_TIMEOUT_MAX is the highest usable value (in microseconds) of that type, and depends on the system threading API. - + NOTE: this isn't the same value as `_thread.TIMEOUT_MAX`. The _thread module exposes a higher-level API, with timeouts expressed in seconds and floating-point numbers allowed. @@ -74,6 +74,8 @@ PyAPI_FUNC(size_t) PyThread_get_stacksize(void); PyAPI_FUNC(int) PyThread_set_stacksize(size_t); +PyAPI_FUNC(PyObject*) _PyThread_Info(void); + /* Thread Local Storage (TLS) API */ PyAPI_FUNC(int) PyThread_create_key(void); PyAPI_FUNC(void) PyThread_delete_key(int); 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 @@ -27,12 +27,15 @@ # and unmaintained) linuxthreads threading library. There's an issue # when combining linuxthreads with a failed execv call: see # http://bugs.python.org/issue4970. -if (hasattr(os, "confstr_names") and - "CS_GNU_LIBPTHREAD_VERSION" in os.confstr_names): - libpthread = os.confstr("CS_GNU_LIBPTHREAD_VERSION") - USING_LINUXTHREADS= libpthread.startswith("linuxthreads") -else: - USING_LINUXTHREADS= False +USING_LINUXTHREADS = False +if threading: + info = threading._info() + try: + pthread_version = info['pthread_version'] + except KeyError: + pass + else: + USING_LINUXTHREADS = pthread_version.startswith("linuxthreads") # Tests creating TESTFN class FileTests(unittest.TestCase): diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py --- a/Lib/test/test_threading.py +++ b/Lib/test/test_threading.py @@ -718,6 +718,17 @@ class BarrierTests(lock_tests.BarrierTests): barriertype = staticmethod(threading.Barrier) + +class MiscTests(unittest.TestCase): + def test_info(self): + info = threading._info() + self.assertIn(info['name'], + 'nt os2 pthread solaris'.split()) + if info['name'] == 'pthread': + self.assertIn(info['lock_implementation'], + ('semaphore', 'mutex+cond')) + + def test_main(): test.support.run_unittest(LockTests, PyRLockTests, CRLockTests, EventTests, ConditionAsRLockTests, ConditionTests, @@ -725,7 +736,7 @@ ThreadTests, ThreadJoinOnShutdown, ThreadingExceptionTests, - BarrierTests + BarrierTests, MiscTests, ) if __name__ == "__main__": diff --git a/Lib/test/test_threadsignals.py b/Lib/test/test_threadsignals.py --- a/Lib/test/test_threadsignals.py +++ b/Lib/test/test_threadsignals.py @@ -14,6 +14,9 @@ process_pid = os.getpid() signalled_all=thread.allocate_lock() +info = thread.info() +USING_PTHREAD_COND = (info['name'] == 'pthread' + and info['lock_implementation'] == 'mutex+cond') def registerSignals(for_usr1, for_usr2, for_alrm): usr1 = signal.signal(signal.SIGUSR1, for_usr1) @@ -70,6 +73,8 @@ def alarm_interrupt(self, sig, frame): raise KeyboardInterrupt + @unittest.skipIf(USING_PTHREAD_COND, + 'POSIX condition variables cannot be interrupted') def test_lock_acquire_interruption(self): # Mimic receiving a SIGINT (KeyboardInterrupt) with SIGALRM while stuck # in a deadlock. @@ -91,6 +96,8 @@ finally: signal.signal(signal.SIGALRM, oldalrm) + @unittest.skipIf(USING_PTHREAD_COND, + 'POSIX condition variables cannot be interrupted') def test_rlock_acquire_interruption(self): # Mimic receiving a SIGINT (KeyboardInterrupt) with SIGALRM while stuck # in a deadlock. diff --git a/Lib/threading.py b/Lib/threading.py --- a/Lib/threading.py +++ b/Lib/threading.py @@ -19,7 +19,7 @@ __all__ = ['active_count', 'Condition', 'current_thread', 'enumerate', 'Event', 'Lock', 'RLock', 'Semaphore', 'BoundedSemaphore', 'Thread', 'Barrier', - 'Timer', 'setprofile', 'settrace', 'local', 'stack_size'] + 'Timer', 'setprofile', 'settrace', 'local', 'stack_size', '_info'] # Rename some stuff so "from threading import *" is safe _start_new_thread = _thread.start_new_thread @@ -31,6 +31,7 @@ except AttributeError: _CRLock = None TIMEOUT_MAX = _thread.TIMEOUT_MAX +_info = _thread.info del _thread diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -110,6 +110,9 @@ Library ------- +- Issue #11223: Add threading._info() function providing informations about + the thread implementation. + - Issue #11731: simplify/enhance email parser/generator API by introducing policy objects. @@ -463,9 +466,9 @@ - Issue #11268: Prevent Mac OS X Installer failure if Documentation package had previously been installed. - + - Issue #11495: OSF support is eliminated. It was deprecated in Python 3.2. - + IDLE ---- @@ -487,6 +490,12 @@ Tests ----- +- Issue #11223: Skip test_lock_acquire_interruption() and + test_rlock_acquire_interruption() of test_threadsignals if a thread lock is + implemented using a POSIX mutex and a POSIX condition variable. A POSIX + condition variable cannot be interrupted by a signal (e.g. on Linux, the + futex system call is restarted). + - Issue #11790: Fix sporadic failures in test_multiprocessing.WithProcessesTestCondition. - Fix possible "file already exists" error when running the tests in parallel. diff --git a/Modules/_threadmodule.c b/Modules/_threadmodule.c --- a/Modules/_threadmodule.c +++ b/Modules/_threadmodule.c @@ -1221,13 +1221,22 @@ (4kB pages are common; using multiples of 4096 for the stack size is\n\ the suggested approach in the absence of more specific information)."); +static PyObject * +thread_info(PyObject *self) +{ + return _PyThread_Info(); +} + +PyDoc_STRVAR(thread_info_doc, +"info() -> dict\n\ +\n\ +Informations about the thread implementation."); + static PyMethodDef thread_methods[] = { {"start_new_thread", (PyCFunction)thread_PyThread_start_new_thread, - METH_VARARGS, - start_new_doc}, + METH_VARARGS, start_new_doc}, {"start_new", (PyCFunction)thread_PyThread_start_new_thread, - METH_VARARGS, - start_new_doc}, + METH_VARARGS, start_new_doc}, {"allocate_lock", (PyCFunction)thread_PyThread_allocate_lock, METH_NOARGS, allocate_doc}, {"allocate", (PyCFunction)thread_PyThread_allocate_lock, @@ -1243,8 +1252,9 @@ {"_count", (PyCFunction)thread__count, METH_NOARGS, _count_doc}, {"stack_size", (PyCFunction)thread_stack_size, - METH_VARARGS, - stack_size_doc}, + METH_VARARGS, stack_size_doc}, + {"info", (PyCFunction)thread_info, + METH_NOARGS, thread_info_doc}, {NULL, NULL} /* sentinel */ }; @@ -1310,7 +1320,7 @@ d = PyModule_GetDict(m); ThreadError = PyExc_RuntimeError; Py_INCREF(ThreadError); - + PyDict_SetItemString(d, "error", ThreadError); Locktype.tp_doc = lock_doc; Py_INCREF(&Locktype); diff --git a/Python/thread.c b/Python/thread.c --- a/Python/thread.c +++ b/Python/thread.c @@ -100,6 +100,7 @@ #endif #ifdef SOLARIS_THREADS +#define PYTHREAD_NAME "solaris" #include "thread_solaris.h" #endif @@ -115,6 +116,7 @@ #endif #ifdef _POSIX_THREADS +#define PYTHREAD_NAME "pthread" #include "thread_pthread.h" #endif @@ -124,14 +126,17 @@ #endif #ifdef NT_THREADS +#define PYTHREAD_NAME "nt" #include "thread_nt.h" #endif #ifdef OS2_THREADS +#define PYTHREAD_NAME "os2" #include "thread_os2.h" #endif #ifdef PLAN9_THREADS +#define PYTHREAD_NAME "plan9" #include "thread_plan9.h" #endif @@ -409,3 +414,55 @@ } #endif /* Py_HAVE_NATIVE_TLS */ + +PyObject* +_PyThread_Info(void) +{ + PyObject *info, *value; + int ret; + char buffer[255]; + int len; + + info = PyDict_New(); + if (info == NULL) + return NULL; + + value = PyUnicode_FromString(PYTHREAD_NAME); + ret = PyDict_SetItemString(info, "name", value); + Py_DECREF(value); + if (ret) + goto error; + +#ifdef _POSIX_THREADS +#ifdef USE_SEMAPHORES + value = PyUnicode_FromString("semaphore"); +#else + value = PyUnicode_FromString("mutex+cond"); +#endif + if (value == NULL) + return NULL; + ret = PyDict_SetItemString(info, "lock_implementation", value); + Py_DECREF(value); + if (ret) + goto error; + +#if defined(HAVE_CONFSTR) && defined(_CS_GNU_LIBPTHREAD_VERSION) + len = confstr(_CS_GNU_LIBPTHREAD_VERSION, buffer, sizeof(buffer)); + if (0 < len && len < sizeof(buffer)) { + value = PyUnicode_DecodeFSDefaultAndSize(buffer, len-1); + if (value == NULL) + goto error; + ret = PyDict_SetItemString(info, "pthread_version", value); + Py_DECREF(value); + if (ret) + goto error; + } +#endif +#endif + + return info; + +error: + Py_DECREF(info); + return NULL; +} -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 20 00:28:36 2011 From: python-checkins at python.org (victor.stinner) Date: Wed, 20 Apr 2011 00:28:36 +0200 Subject: [Python-checkins] cpython: Issue #11223: fix test_dummy_threading, add _dummy_thread.info() Message-ID: http://hg.python.org/cpython/rev/bc1c6bd7eeb0 changeset: 69458:bc1c6bd7eeb0 user: Victor Stinner date: Wed Apr 20 00:26:28 2011 +0200 summary: Issue #11223: fix test_dummy_threading, add _dummy_thread.info() files: Lib/_dummy_thread.py | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/Lib/_dummy_thread.py b/Lib/_dummy_thread.py --- a/Lib/_dummy_thread.py +++ b/Lib/_dummy_thread.py @@ -149,3 +149,6 @@ else: global _interrupt _interrupt = True + +def info(): + return {'name': 'dummy'} -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 20 02:01:11 2011 From: python-checkins at python.org (raymond.hettinger) Date: Wed, 20 Apr 2011 02:01:11 +0200 Subject: [Python-checkins] cpython (2.7): Issue #11875: Alter the previous fix to work better with subclasses Message-ID: http://hg.python.org/cpython/rev/db66eaf353a6 changeset: 69459:db66eaf353a6 branch: 2.7 parent: 69452:08b5e2c9112c user: Raymond Hettinger date: Tue Apr 19 16:53:07 2011 -0700 summary: Issue #11875: Alter the previous fix to work better with subclasses files: Lib/collections.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/collections.py b/Lib/collections.py --- a/Lib/collections.py +++ b/Lib/collections.py @@ -116,7 +116,7 @@ 'Return state information for pickling' items = [[k, self[k]] for k in self] inst_dict = vars(self).copy() - for k in vars(self.__class__()): + for k in vars(OrderedDict()): inst_dict.pop(k, None) if inst_dict: return (self.__class__, (items,), inst_dict) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 20 02:19:26 2011 From: python-checkins at python.org (raymond.hettinger) Date: Wed, 20 Apr 2011 02:19:26 +0200 Subject: [Python-checkins] cpython (3.1): Issue #11875: Alter the previous fix to work better with subclasses Message-ID: http://hg.python.org/cpython/rev/408f23b6cec5 changeset: 69460:408f23b6cec5 branch: 3.1 parent: 69453:fb261fa85429 user: Raymond Hettinger date: Tue Apr 19 17:17:23 2011 -0700 summary: Issue #11875: Alter the previous fix to work better with subclasses files: Lib/collections.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/collections.py b/Lib/collections.py --- a/Lib/collections.py +++ b/Lib/collections.py @@ -102,7 +102,7 @@ 'Return state information for pickling' items = [[k, self[k]] for k in self] inst_dict = vars(self).copy() - for k in vars(self.__class__()): + for k in vars(OrderedDict()): inst_dict.pop(k, None) if inst_dict: return (self.__class__, (items,), inst_dict) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 20 02:19:26 2011 From: python-checkins at python.org (raymond.hettinger) Date: Wed, 20 Apr 2011 02:19:26 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): Issue #11875: Alter the previous fix to work better with subclasses Message-ID: http://hg.python.org/cpython/rev/4e6840477d96 changeset: 69461:4e6840477d96 branch: 3.2 parent: 69454:9179bd4037ad parent: 69460:408f23b6cec5 user: Raymond Hettinger date: Tue Apr 19 17:17:51 2011 -0700 summary: Issue #11875: Alter the previous fix to work better with subclasses files: Lib/collections.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/collections.py b/Lib/collections.py --- a/Lib/collections.py +++ b/Lib/collections.py @@ -155,7 +155,7 @@ 'Return state information for pickling' items = [[k, self[k]] for k in self] inst_dict = vars(self).copy() - for k in vars(self.__class__()): + for k in vars(OrderedDict()): inst_dict.pop(k, None) if inst_dict: return (self.__class__, (items,), inst_dict) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 20 02:19:28 2011 From: python-checkins at python.org (raymond.hettinger) Date: Wed, 20 Apr 2011 02:19:28 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Issue #11875: Alter the previous fix to work better with subclasses Message-ID: http://hg.python.org/cpython/rev/64968d226b61 changeset: 69462:64968d226b61 parent: 69458:bc1c6bd7eeb0 parent: 69461:4e6840477d96 user: Raymond Hettinger date: Tue Apr 19 17:19:11 2011 -0700 summary: Issue #11875: Alter the previous fix to work better with subclasses files: Lib/collections/__init__.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/collections/__init__.py b/Lib/collections/__init__.py --- a/Lib/collections/__init__.py +++ b/Lib/collections/__init__.py @@ -156,7 +156,7 @@ 'Return state information for pickling' items = [[k, self[k]] for k in self] inst_dict = vars(self).copy() - for k in vars(self.__class__()): + for k in vars(OrderedDict()): inst_dict.pop(k, None) if inst_dict: return (self.__class__, (items,), inst_dict) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 20 03:28:31 2011 From: python-checkins at python.org (victor.stinner) Date: Wed, 20 Apr 2011 03:28:31 +0200 Subject: [Python-checkins] cpython: Close #11619: write_compiled_module() doesn't encode the filename Message-ID: http://hg.python.org/cpython/rev/e4e92d68ba3a changeset: 69463:e4e92d68ba3a user: Victor Stinner date: Wed Apr 20 03:27:51 2011 +0200 summary: Close #11619: write_compiled_module() doesn't encode the filename Reimplement open_exclusive() using _wopen() to avoid encoding the filename to the filesystem encoding: use the Unicode version of the Windows API. files: Python/import.c | 26 ++++++++++++++++++++++++-- 1 files changed, 24 insertions(+), 2 deletions(-) diff --git a/Python/import.c b/Python/import.c --- a/Python/import.c +++ b/Python/import.c @@ -1198,6 +1198,7 @@ /* Helper to open a bytecode file for writing in exclusive mode */ +#ifndef MS_WINDOWS static FILE * open_exclusive(char *filename, mode_t mode) { @@ -1228,6 +1229,7 @@ return fopen(filename, "wb"); #endif } +#endif /* Write a compiled module to a file, placing the time of last @@ -1250,7 +1252,12 @@ S_IWUSR | S_IWGRP | S_IWOTH); PyObject *dirbytes; #endif - PyObject *cpathbytes, *dirname; +#ifdef MS_WINDOWS + int fd; +#else + PyObject *cpathbytes; +#endif + PyObject *dirname; Py_UNICODE *dirsep; int res, ok; @@ -1294,6 +1301,16 @@ } Py_DECREF(dirname); +#ifdef MS_WINDOWS + (void)DeleteFileW(PyUnicode_AS_UNICODE(cpathname)); + fd = _wopen(PyUnicode_AS_UNICODE(cpathname), + O_EXCL | O_CREAT | O_WRONLY | O_TRUNC | O_BINARY, + mode); + if (0 <= fd) + fp = fdopen(fd, "wb"); + else + fp = NULL; +#else cpathbytes = PyUnicode_EncodeFSDefault(cpathname); if (cpathbytes == NULL) { PyErr_Clear(); @@ -1301,11 +1318,14 @@ } fp = open_exclusive(PyBytes_AS_STRING(cpathbytes), mode); +#endif if (fp == NULL) { if (Py_VerboseFlag) PySys_FormatStderr( "# can't create %R\n", cpathname); +#ifndef MS_WINDOWS Py_DECREF(cpathbytes); +#endif return; } PyMarshal_WriteLongToFile(pyc_magic, fp, Py_MARSHAL_VERSION); @@ -1321,11 +1341,13 @@ (void)DeleteFileW(PyUnicode_AS_UNICODE(cpathname)); #else (void) unlink(PyBytes_AS_STRING(cpathbytes)); + Py_DECREF(cpathbytes); #endif - Py_DECREF(cpathbytes); return; } +#ifndef MS_WINDOWS Py_DECREF(cpathbytes); +#endif /* Now write the true mtime */ fseek(fp, 4L, 0); assert(mtime < LONG_MAX); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 20 04:16:02 2011 From: python-checkins at python.org (brian.curtin) Date: Wed, 20 Apr 2011 04:16:02 +0200 Subject: [Python-checkins] cpython (2.7): Fix #8886. Use context managers throughout zipfile tests. Message-ID: http://hg.python.org/cpython/rev/83a426e969f5 changeset: 69464:83a426e969f5 branch: 2.7 parent: 69459:db66eaf353a6 user: Brian Curtin date: Tue Apr 19 21:15:55 2011 -0500 summary: Fix #8886. Use context managers throughout zipfile tests. This was fixed in py3k SVN. Consider this a backport. files: Lib/test/test_zipfile.py | 218 +++++++++++++------------- 1 files changed, 108 insertions(+), 110 deletions(-) diff --git a/Lib/test/test_zipfile.py b/Lib/test/test_zipfile.py --- a/Lib/test/test_zipfile.py +++ b/Lib/test/test_zipfile.py @@ -115,20 +115,20 @@ # Read the ZIP archive with zipfile.ZipFile(f, "r", compression) as zipfp: zipdata1 = [] - zipopen1 = zipfp.open(TESTFN) - while True: - read_data = zipopen1.read(256) - if not read_data: - break - zipdata1.append(read_data) + with zipfp.open(TESTFN) as zipopen1: + while True: + read_data = zipopen1.read(256) + if not read_data: + break + zipdata1.append(read_data) zipdata2 = [] - zipopen2 = zipfp.open("another.name") - while True: - read_data = zipopen2.read(256) - if not read_data: - break - zipdata2.append(read_data) + with zipfp.open("another.name") as zipopen2: + while True: + read_data = zipopen2.read(256) + if not read_data: + break + zipdata2.append(read_data) self.assertEqual(''.join(zipdata1), self.data) self.assertEqual(''.join(zipdata2), self.data) @@ -147,7 +147,8 @@ infos = zipfp.infolist() data = "" for info in infos: - data += zipfp.open(info).read() + with zipfp.open(info) as f: + data += f.read() self.assertTrue(data == "foobar" or data == "barfoo") data = "" for info in infos: @@ -160,12 +161,12 @@ # Read the ZIP archive with zipfile.ZipFile(f, "r", compression) as zipfp: zipdata1 = [] - zipopen1 = zipfp.open(TESTFN) - while True: - read_data = zipopen1.read(randint(1, 1024)) - if not read_data: - break - zipdata1.append(read_data) + with zipfp.open(TESTFN) as zipopen1: + while True: + read_data = zipopen1.read(randint(1, 1024)) + if not read_data: + break + zipdata1.append(read_data) self.assertEqual(''.join(zipdata1), self.data) @@ -177,16 +178,14 @@ f = StringIO() data = 'a\r\n' * 16 * 1024 - zipfp = zipfile.ZipFile(f, 'w', zipfile.ZIP_STORED) - zipfp.writestr(TESTFN, data) - zipfp.close() + with zipfile.ZipFile(f, 'w', zipfile.ZIP_STORED) as zipfp: + zipfp.writestr(TESTFN, data) data2 = '' - zipfp = zipfile.ZipFile(f, 'r') - zipopen = zipfp.open(TESTFN, 'rU') - for line in zipopen: - data2 += line - zipfp.close() + with zipfile.ZipFile(f, 'r') as zipfp: + with zipfp.open(TESTFN, 'rU') as zipopen: + for line in zipopen: + data2 += line self.assertEqual(data, data2.replace('\n', '\r\n')) @@ -194,42 +193,41 @@ self.make_test_archive(f, compression) # Read the ZIP archive - zipfp = zipfile.ZipFile(f, "r") - zipopen = zipfp.open(TESTFN) + with zipfile.ZipFile(f, "r") as zipfp: + with zipfp.open(TESTFN) as zipopen: + data = '' + while True: + read = zipopen.readline() + if not read: + break + data += read - data = '' - while True: - read = zipopen.readline() - if not read: - break - data += read - - read = zipopen.read(100) - if not read: - break - data += read + read = zipopen.read(100) + if not read: + break + data += read self.assertEqual(data, self.data) - zipfp.close() def zip_readline_test(self, f, compression): self.make_test_archive(f, compression) # Read the ZIP archive with zipfile.ZipFile(f, "r") as zipfp: - zipopen = zipfp.open(TESTFN) - for line in self.line_gen: - linedata = zipopen.readline() - self.assertEqual(linedata, line + '\n') + with zipfp.open(TESTFN) as zipopen: + for line in self.line_gen: + linedata = zipopen.readline() + self.assertEqual(linedata, line + '\n') def zip_readlines_test(self, f, compression): self.make_test_archive(f, compression) # Read the ZIP archive with zipfile.ZipFile(f, "r") as zipfp: - ziplines = zipfp.open(TESTFN).readlines() - for line, zipline in zip(self.line_gen, ziplines): - self.assertEqual(zipline, line + '\n') + with zipfp.open(TESTFN) as zo: + ziplines = zo.readlines() + for line, zipline in zip(self.line_gen, ziplines): + self.assertEqual(zipline, line + '\n') def zip_iterlines_test(self, f, compression): self.make_test_archive(f, compression) @@ -301,9 +299,9 @@ # Get an open object for strfile with zipfile.ZipFile(TESTFN2, "r", zipfile.ZIP_DEFLATED) as zipfp: - openobj = zipfp.open("strfile") - self.assertEqual(openobj.read(1), '1') - self.assertEqual(openobj.read(1), '2') + with zipfp.open("strfile") as openobj: + self.assertEqual(openobj.read(1), '1') + self.assertEqual(openobj.read(1), '2') def test_absolute_arcnames(self): with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp: @@ -775,8 +773,8 @@ self.assertRaises(IOError, zipfile.ZipFile, TESTFN) def test_empty_file_raises_BadZipFile(self): - f = open(TESTFN, 'w') - f.close() + with open(TESTFN, 'w') as f: + pass self.assertRaises(zipfile.BadZipfile, zipfile.ZipFile, TESTFN) with open(TESTFN, 'w') as fp: @@ -820,11 +818,11 @@ with zipfile.ZipFile(TESTFN, mode="w") as zipf: zipf.writestr("foo.txt", "O, for a Muse of Fire!") # read the data to make sure the file is there - f = zipf.open("foo.txt") - for i in xrange(FIXEDTEST_SIZE): - self.assertEqual(f.read(0), '') + with zipf.open("foo.txt") as f: + for i in xrange(FIXEDTEST_SIZE): + self.assertEqual(f.read(0), '') - self.assertEqual(f.read(), "O, for a Muse of Fire!") + self.assertEqual(f.read(), "O, for a Muse of Fire!") def test_open_non_existent_item(self): """Check that attempting to call open() for an item that doesn't @@ -952,15 +950,15 @@ def test_empty_zipfile(self): # Check that creating a file in 'w' or 'a' mode and closing without # adding any files to the archives creates a valid empty ZIP file - zipf = zipfile.ZipFile(TESTFN, mode="w") - zipf.close() + with zipfile.ZipFile(TESTFN, mode="w") as zipf: + pass try: zipf = zipfile.ZipFile(TESTFN, mode="r") except zipfile.BadZipfile: self.fail("Unable to create empty ZIP file in 'w' mode") - zipf = zipfile.ZipFile(TESTFN, mode="a") - zipf.close() + with zipfile.ZipFile(TESTFN, mode="a") as zipf: + pass try: zipf = zipfile.ZipFile(TESTFN, mode="r") except: @@ -970,8 +968,8 @@ # Issue 1710703: Check that opening a file with less than 22 bytes # raises a BadZipfile exception (rather than the previously unhelpful # IOError) - f = open(TESTFN, 'w') - f.close() + with open(TESTFN, 'w') as f: + pass self.assertRaises(zipfile.BadZipfile, zipfile.ZipFile, TESTFN, 'r') def tearDown(self): @@ -1084,20 +1082,20 @@ # Read the ZIP archive with zipfile.ZipFile(f, "r", compression) as zipfp: zipdata1 = [] - zipopen1 = zipfp.open(TESTFN) - while True: - read_data = zipopen1.read(256) - if not read_data: - break - zipdata1.append(read_data) + with zipfp.open(TESTFN) as zipopen1: + while True: + read_data = zipopen1.read(256) + if not read_data: + break + zipdata1.append(read_data) zipdata2 = [] - zipopen2 = zipfp.open("another.name") - while True: - read_data = zipopen2.read(256) - if not read_data: - break - zipdata2.append(read_data) + with zipfp.open("another.name") as zipopen2: + while True: + read_data = zipopen2.read(256) + if not read_data: + break + zipdata2.append(read_data) testdata1 = ''.join(zipdata1) self.assertEqual(len(testdata1), len(self.data)) @@ -1122,12 +1120,12 @@ # Read the ZIP archive with zipfile.ZipFile(f, "r", compression) as zipfp: zipdata1 = [] - zipopen1 = zipfp.open(TESTFN) - while True: - read_data = zipopen1.read(randint(1, 1024)) - if not read_data: - break - zipdata1.append(read_data) + with zipfp.open(TESTFN) as zipopen1: + while True: + read_data = zipopen1.read(randint(1, 1024)) + if not read_data: + break + zipdata1.append(read_data) testdata = ''.join(zipdata1) self.assertEqual(len(testdata), len(self.data)) @@ -1167,12 +1165,11 @@ # Verify that (when the ZipFile is in control of creating file objects) # multiple open() calls can be made without interfering with each other. with zipfile.ZipFile(TESTFN2, mode="r") as zipf: - zopen1 = zipf.open('ones') - zopen2 = zipf.open('twos') - data1 = zopen1.read(500) - data2 = zopen2.read(500) - data1 += zopen1.read(500) - data2 += zopen2.read(500) + with zipf.open('ones') as zopen1, zipf.open('twos') as zopen2: + data1 = zopen1.read(500) + data2 = zopen2.read(500) + data1 += zopen1.read(500) + data2 += zopen2.read(500) self.assertEqual(data1, '1'*FIXEDTEST_SIZE) self.assertEqual(data2, '2'*FIXEDTEST_SIZE) @@ -1180,12 +1177,11 @@ # Verify that (when the ZipFile is in control of creating file objects) # multiple open() calls can be made without interfering with each other. with zipfile.ZipFile(TESTFN2, mode="r") as zipf: - zopen1 = zipf.open('ones') - data1 = zopen1.read(500) - zopen2 = zipf.open('twos') - data2 = zopen2.read(500) - data1 += zopen1.read(500) - data2 += zopen2.read(500) + with zipf.open('ones') as zopen1, zipf.open('twos') as zopen2: + data1 = zopen1.read(500) + data2 = zopen2.read(500) + data1 += zopen1.read(500) + data2 += zopen2.read(500) self.assertEqual(data1, '1'*FIXEDTEST_SIZE) self.assertEqual(data2, '2'*FIXEDTEST_SIZE) @@ -1244,7 +1240,8 @@ # Read the ZIP archive with zipfile.ZipFile(f, "r") as zipfp: for sep, fn in self.arcfiles.items(): - zipdata = zipfp.open(fn, "rU").read() + with zipfp.open(fn, "rU") as fp: + zipdata = fp.read() self.assertEqual(self.arcdata[sep], zipdata) def readline_read_test(self, f, compression): @@ -1253,18 +1250,18 @@ # Read the ZIP archive zipfp = zipfile.ZipFile(f, "r") for sep, fn in self.arcfiles.items(): - zipopen = zipfp.open(fn, "rU") - data = '' - while True: - read = zipopen.readline() - if not read: - break - data += read + with zipfp.open(fn, "rU") as zipopen: + data = '' + while True: + read = zipopen.readline() + if not read: + break + data += read - read = zipopen.read(5) - if not read: - break - data += read + read = zipopen.read(5) + if not read: + break + data += read self.assertEqual(data, self.arcdata['\n']) @@ -1276,10 +1273,10 @@ # Read the ZIP archive with zipfile.ZipFile(f, "r") as zipfp: for sep, fn in self.arcfiles.items(): - zipopen = zipfp.open(fn, "rU") - for line in self.line_gen: - linedata = zipopen.readline() - self.assertEqual(linedata, line + '\n') + with zipfp.open(fn, "rU") as zipopen: + for line in self.line_gen: + linedata = zipopen.readline() + self.assertEqual(linedata, line + '\n') def readlines_test(self, f, compression): self.make_test_archive(f, compression) @@ -1287,7 +1284,8 @@ # Read the ZIP archive with zipfile.ZipFile(f, "r") as zipfp: for sep, fn in self.arcfiles.items(): - ziplines = zipfp.open(fn, "rU").readlines() + with zipfp.open(fn, "rU") as fp: + ziplines = fp.readlines() for line, zipline in zip(self.line_gen, ziplines): self.assertEqual(zipline, line + '\n') -- Repository URL: http://hg.python.org/cpython From tjreedy at udel.edu Wed Apr 20 04:42:02 2011 From: tjreedy at udel.edu (Terry Reedy) Date: Tue, 19 Apr 2011 22:42:02 -0400 Subject: [Python-checkins] cpython: Issue #11223: Add threading._info() function providing informations about the In-Reply-To: References: Message-ID: <4DAE47FA.7080007@udel.edu> On 4/19/2011 5:59 PM, victor.stinner wrote: > Issue #11223: Add threading._info() function providing informations about the > thread implementation. Since this is being documented, making it part of the public api, why does it have a leading underscore? tjr From solipsis at pitrou.net Wed Apr 20 04:58:54 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Wed, 20 Apr 2011 04:58:54 +0200 Subject: [Python-checkins] Daily reference leaks (e4e92d68ba3a): sum=-56 Message-ID: results for e4e92d68ba3a on branch "default" -------------------------------------------- test_pyexpat leaked [0, 0, -56] references, sum=-56 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/refloggEPIc1', '-x'] From python-checkins at python.org Wed Apr 20 11:58:14 2011 From: python-checkins at python.org (vinay.sajip) Date: Wed, 20 Apr 2011 11:58:14 +0200 Subject: [Python-checkins] cpython: Attempt fix of #11557 by changing teardown logic. Message-ID: http://hg.python.org/cpython/rev/41dc66528c4e changeset: 69465:41dc66528c4e parent: 69463:e4e92d68ba3a user: Vinay Sajip date: Wed Apr 20 10:58:06 2011 +0100 summary: Attempt fix of #11557 by changing teardown logic. files: Lib/test/test_logging.py | 13 +++++++++---- 1 files changed, 9 insertions(+), 4 deletions(-) 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 @@ -2414,15 +2414,20 @@ def setUp(self): super(BasicConfigTest, self).setUp() - handlers = logging.root.handlers - self.addCleanup(lambda: setattr(logging.root, 'handlers', handlers)) + self.handlers = logging.root.handlers + self.addCleanup(self.cleanup) logging.root.handlers = [] def tearDown(self): - logging.shutdown() + for h in logging.root.handlers[:]: + logging.root.removeHandler(h) + h.close() super(BasicConfigTest, self).tearDown() - @unittest.skipIf(True, "test disabled, issue #11557") + def cleanup(self): + setattr(logging.root, 'handlers', self.handlers) + + #@unittest.skipIf(True, "test disabled, issue #11557") def test_no_kwargs(self): logging.basicConfig() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 20 12:24:04 2011 From: python-checkins at python.org (victor.stinner) Date: Wed, 20 Apr 2011 12:24:04 +0200 Subject: [Python-checkins] cpython: Issue #11223: fix compiler warnings Message-ID: http://hg.python.org/cpython/rev/64008d17fb54 changeset: 69466:64008d17fb54 user: Victor Stinner date: Wed Apr 20 12:23:26 2011 +0200 summary: Issue #11223: fix compiler warnings files: Python/thread.c | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/Python/thread.c b/Python/thread.c --- a/Python/thread.c +++ b/Python/thread.c @@ -420,8 +420,11 @@ { PyObject *info, *value; int ret; +#if (defined(_POSIX_THREADS) && defined(HAVE_CONFSTR) \ + && defined(_CS_GNU_LIBPTHREAD_VERSION)) char buffer[255]; int len; +#endif info = PyDict_New(); if (info == NULL) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 20 12:51:05 2011 From: python-checkins at python.org (vinay.sajip) Date: Wed, 20 Apr 2011 12:51:05 +0200 Subject: [Python-checkins] cpython: Attempt fix of #11557 by changing setup/teardown logic. Message-ID: http://hg.python.org/cpython/rev/31bb4788aa1c changeset: 69467:31bb4788aa1c user: Vinay Sajip date: Wed Apr 20 11:50:56 2011 +0100 summary: Attempt fix of #11557 by changing setup/teardown logic. files: Lib/test/test_logging.py | 7 ++++++- 1 files changed, 6 insertions(+), 1 deletions(-) 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 @@ -2410,11 +2410,13 @@ class BasicConfigTest(unittest.TestCase): - """Tets suite for logging.basicConfig.""" + """Test suite for logging.basicConfig.""" def setUp(self): super(BasicConfigTest, self).setUp() self.handlers = logging.root.handlers + self.saved_handlers = logging._handlers.copy() + self.saved_handler_list = logging._handlerList[:] self.addCleanup(self.cleanup) logging.root.handlers = [] @@ -2426,6 +2428,9 @@ def cleanup(self): setattr(logging.root, 'handlers', self.handlers) + logging._handlers.clear() + logging._handlers.update(self.saved_handlers) + logging._handlerList[:] = self.saved_handler_list #@unittest.skipIf(True, "test disabled, issue #11557") def test_no_kwargs(self): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 20 13:21:00 2011 From: python-checkins at python.org (vinay.sajip) Date: Wed, 20 Apr 2011 13:21:00 +0200 Subject: [Python-checkins] cpython: Attempt fix of #11557 by refining setup/teardown logic. Message-ID: http://hg.python.org/cpython/rev/0494afdc8615 changeset: 69468:0494afdc8615 user: Vinay Sajip date: Wed Apr 20 12:20:44 2011 +0100 summary: Attempt fix of #11557 by refining setup/teardown logic. files: Lib/test/test_logging.py | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) 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 @@ -2417,6 +2417,7 @@ self.handlers = logging.root.handlers self.saved_handlers = logging._handlers.copy() self.saved_handler_list = logging._handlerList[:] + self.original_logging_level = logging.root.level self.addCleanup(self.cleanup) logging.root.handlers = [] @@ -2431,6 +2432,7 @@ logging._handlers.clear() logging._handlers.update(self.saved_handlers) logging._handlerList[:] = self.saved_handler_list + logging.root.level = self.original_logging_level #@unittest.skipIf(True, "test disabled, issue #11557") def test_no_kwargs(self): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 20 13:50:50 2011 From: python-checkins at python.org (vinay.sajip) Date: Wed, 20 Apr 2011 13:50:50 +0200 Subject: [Python-checkins] cpython: Attempt fix of #11557 by refining test logic. Message-ID: http://hg.python.org/cpython/rev/d93e18e6a3e8 changeset: 69469:d93e18e6a3e8 user: Vinay Sajip date: Wed Apr 20 12:50:42 2011 +0100 summary: Attempt fix of #11557 by refining test logic. files: Lib/test/test_logging.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) 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 @@ -2453,7 +2453,7 @@ self.assertIsInstance(formatter._style, logging.PercentStyle) # level is not explicitely set - self.assertEqual(logging.root.level, logging.WARNING) + self.assertEqual(logging.root.level, self.original_logging_level) def test_filename(self): logging.basicConfig(filename='test.log') -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 20 16:41:22 2011 From: python-checkins at python.org (vinay.sajip) Date: Wed, 20 Apr 2011 16:41:22 +0200 Subject: [Python-checkins] cpython: Tidied comments and docstrings. Message-ID: http://hg.python.org/cpython/rev/dd8d999713f4 changeset: 69470:dd8d999713f4 user: Vinay Sajip date: Wed Apr 20 15:41:14 2011 +0100 summary: Tidied comments and docstrings. files: Lib/test/test_logging.py | 5 ++--- 1 files changed, 2 insertions(+), 3 deletions(-) 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 @@ -2255,7 +2255,7 @@ class ShutdownTest(BaseTest): - """Tets suite for the shutdown method.""" + """Test suite for the shutdown method.""" def setUp(self): super(ShutdownTest, self).setUp() @@ -2342,7 +2342,7 @@ class ModuleLevelMiscTest(BaseTest): - """Tets suite for some module level methods.""" + """Test suite for some module level methods.""" def test_disable(self): old_disable = logging.root.manager.disable @@ -2434,7 +2434,6 @@ logging._handlerList[:] = self.saved_handler_list logging.root.level = self.original_logging_level - #@unittest.skipIf(True, "test disabled, issue #11557") def test_no_kwargs(self): logging.basicConfig() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 20 17:59:51 2011 From: python-checkins at python.org (jesus.cea) Date: Wed, 20 Apr 2011 17:59:51 +0200 Subject: [Python-checkins] cpython (2.7): startswith and endswith don't accept None as slice index. Patch by Torsten Message-ID: http://hg.python.org/cpython/rev/f4da64529e8c changeset: 69471:f4da64529e8c branch: 2.7 parent: 69464:83a426e969f5 user: Jesus Cea date: Wed Apr 20 16:39:15 2011 +0200 summary: startswith and endswith don't accept None as slice index. Patch by Torsten Becker. (closes #11828) files: Lib/test/string_tests.py | 57 ++++++++++++++++++++++ Lib/test/test_bytes.py | 62 ++++++++++++++++++++++++ Misc/ACKS | 1 + Misc/NEWS | 3 + Objects/bytearrayobject.c | 13 ++--- Objects/stringlib/find.h | 67 +++++++++++++++++++------- Objects/stringobject.c | 25 ++------- Objects/unicodeobject.c | 35 ++++++------- 8 files changed, 198 insertions(+), 65 deletions(-) diff --git a/Lib/test/string_tests.py b/Lib/test/string_tests.py --- a/Lib/test/string_tests.py +++ b/Lib/test/string_tests.py @@ -1177,6 +1177,63 @@ # mixed use of str and unicode self.assertEqual('a/b/c'.rpartition(u'/'), ('a/b', '/', 'c')) + def test_none_arguments(self): + # issue 11828 + s = 'hello' + self.checkequal(2, s, 'find', 'l', None) + self.checkequal(3, s, 'find', 'l', -2, None) + self.checkequal(2, s, 'find', 'l', None, -2) + self.checkequal(0, s, 'find', 'h', None, None) + + self.checkequal(3, s, 'rfind', 'l', None) + self.checkequal(3, s, 'rfind', 'l', -2, None) + self.checkequal(2, s, 'rfind', 'l', None, -2) + self.checkequal(0, s, 'rfind', 'h', None, None) + + self.checkequal(2, s, 'index', 'l', None) + self.checkequal(3, s, 'index', 'l', -2, None) + self.checkequal(2, s, 'index', 'l', None, -2) + self.checkequal(0, s, 'index', 'h', None, None) + + self.checkequal(3, s, 'rindex', 'l', None) + self.checkequal(3, s, 'rindex', 'l', -2, None) + self.checkequal(2, s, 'rindex', 'l', None, -2) + self.checkequal(0, s, 'rindex', 'h', None, None) + + self.checkequal(2, s, 'count', 'l', None) + self.checkequal(1, s, 'count', 'l', -2, None) + self.checkequal(1, s, 'count', 'l', None, -2) + self.checkequal(0, s, 'count', 'x', None, None) + + self.checkequal(True, s, 'endswith', 'o', None) + self.checkequal(True, s, 'endswith', 'lo', -2, None) + self.checkequal(True, s, 'endswith', 'l', None, -2) + self.checkequal(False, s, 'endswith', 'x', None, None) + + self.checkequal(True, s, 'startswith', 'h', None) + self.checkequal(True, s, 'startswith', 'l', -2, None) + self.checkequal(True, s, 'startswith', 'h', None, -2) + self.checkequal(False, s, 'startswith', 'x', None, None) + + def test_find_etc_raise_correct_error_messages(self): + # issue 11828 + s = 'hello' + x = 'x' + self.assertRaisesRegexp(TypeError, r'\bfind\b', s.find, + x, None, None, None) + self.assertRaisesRegexp(TypeError, r'\brfind\b', s.rfind, + x, None, None, None) + self.assertRaisesRegexp(TypeError, r'\bindex\b', s.index, + x, None, None, None) + self.assertRaisesRegexp(TypeError, r'\brindex\b', s.rindex, + x, None, None, None) + self.assertRaisesRegexp(TypeError, r'^count\(', s.count, + x, None, None, None) + self.assertRaisesRegexp(TypeError, r'^startswith\(', s.startswith, + x, None, None, None) + self.assertRaisesRegexp(TypeError, r'^endswith\(', s.endswith, + x, None, None, None) + class MixinStrStringUserStringTest: # Additional tests for 8bit strings, i.e. str, UserString and # the string module 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 @@ -456,6 +456,68 @@ self.assertEqual([ord(b[i:i+1]) for i in range(len(b))], [0, 65, 127, 128, 255]) + def test_none_arguments(self): + # issue 11828 + b = self.type2test(b'hello') + l = self.type2test(b'l') + h = self.type2test(b'h') + x = self.type2test(b'x') + o = self.type2test(b'o') + + self.assertEqual(2, b.find(l, None)) + self.assertEqual(3, b.find(l, -2, None)) + self.assertEqual(2, b.find(l, None, -2)) + self.assertEqual(0, b.find(h, None, None)) + + self.assertEqual(3, b.rfind(l, None)) + self.assertEqual(3, b.rfind(l, -2, None)) + self.assertEqual(2, b.rfind(l, None, -2)) + self.assertEqual(0, b.rfind(h, None, None)) + + self.assertEqual(2, b.index(l, None)) + self.assertEqual(3, b.index(l, -2, None)) + self.assertEqual(2, b.index(l, None, -2)) + self.assertEqual(0, b.index(h, None, None)) + + self.assertEqual(3, b.rindex(l, None)) + self.assertEqual(3, b.rindex(l, -2, None)) + self.assertEqual(2, b.rindex(l, None, -2)) + self.assertEqual(0, b.rindex(h, None, None)) + + self.assertEqual(2, b.count(l, None)) + self.assertEqual(1, b.count(l, -2, None)) + self.assertEqual(1, b.count(l, None, -2)) + self.assertEqual(0, b.count(x, None, None)) + + self.assertEqual(True, b.endswith(o, None)) + self.assertEqual(True, b.endswith(o, -2, None)) + self.assertEqual(True, b.endswith(l, None, -2)) + self.assertEqual(False, b.endswith(x, None, None)) + + self.assertEqual(True, b.startswith(h, None)) + self.assertEqual(True, b.startswith(l, -2, None)) + self.assertEqual(True, b.startswith(h, None, -2)) + self.assertEqual(False, b.startswith(x, None, None)) + + def test_find_etc_raise_correct_error_messages(self): + # issue 11828 + b = self.type2test(b'hello') + x = self.type2test(b'x') + self.assertRaisesRegexp(TypeError, r'\bfind\b', b.find, + x, None, None, None) + self.assertRaisesRegexp(TypeError, r'\brfind\b', b.rfind, + x, None, None, None) + self.assertRaisesRegexp(TypeError, r'\bindex\b', b.index, + x, None, None, None) + self.assertRaisesRegexp(TypeError, r'\brindex\b', b.rindex, + x, None, None, None) + self.assertRaisesRegexp(TypeError, r'\bcount\b', b.count, + x, None, None, None) + self.assertRaisesRegexp(TypeError, r'\bstartswith\b', b.startswith, + x, None, None, None) + self.assertRaisesRegexp(TypeError, r'\bendswith\b', b.endswith, + x, None, None, None) + class ByteArrayTest(BaseBytesTest): type2test = bytearray diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -60,6 +60,7 @@ David Beazley Robin Becker Neal Becker +Torsten Becker Bill Bedford Reimer Behrends Ben Bell diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -43,6 +43,9 @@ rather than the Py_IsInitialized flag, avoiding a Fatal Python error in certain circumstances when an import is done in __del__. +- issue #11828: startswith and endswith don't accept None as slice index. + Patch by Torsten Becker. + - Issue #10674: Remove unused 'dictmaker' rule from grammar. - Issue #10596: Fix float.__mod__ to have the same behaviour as diff --git a/Objects/bytearrayobject.c b/Objects/bytearrayobject.c --- a/Objects/bytearrayobject.c +++ b/Objects/bytearrayobject.c @@ -1149,8 +1149,8 @@ Py_ssize_t start=0, end=PY_SSIZE_T_MAX; Py_ssize_t res; - if (!PyArg_ParseTuple(args, "O|O&O&:find/rfind/index/rindex", &subobj, - _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) + if (!stringlib_parse_args_finds("find/rfind/index/rindex", + args, &subobj, &start, &end)) return -2; if (_getbuffer(subobj, &subbuf) < 0) return -2; @@ -1200,8 +1200,7 @@ Py_buffer vsub; PyObject *count_obj; - if (!PyArg_ParseTuple(args, "O|O&O&:count", &sub_obj, - _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) + if (!stringlib_parse_args_finds("count", args, &sub_obj, &start, &end)) return NULL; if (_getbuffer(sub_obj, &vsub) < 0) @@ -1359,8 +1358,7 @@ PyObject *subobj; int result; - if (!PyArg_ParseTuple(args, "O|O&O&:startswith", &subobj, - _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) + if (!stringlib_parse_args_finds("startswith", args, &subobj, &start, &end)) return NULL; if (PyTuple_Check(subobj)) { Py_ssize_t i; @@ -1399,8 +1397,7 @@ PyObject *subobj; int result; - if (!PyArg_ParseTuple(args, "O|O&O&:endswith", &subobj, - _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) + if (!stringlib_parse_args_finds("endswith", args, &subobj, &start, &end)) return NULL; if (PyTuple_Check(subobj)) { Py_ssize_t i; diff --git a/Objects/stringlib/find.h b/Objects/stringlib/find.h --- a/Objects/stringlib/find.h +++ b/Objects/stringlib/find.h @@ -93,32 +93,33 @@ #endif /* STRINGLIB_WANT_CONTAINS_OBJ */ -#if STRINGLIB_IS_UNICODE - /* This function is a helper for the "find" family (find, rfind, index, -rindex) of unicodeobject.c file, because they all have the same -behaviour for the arguments. +rindex) and for count, startswith and endswith, because they all have +the same behaviour for the arguments. It does not touch the variables received until it knows everything is ok. - -Note that we receive a pointer to the pointer of the substring object, -so when we create that object in this function we don't DECREF it, -because it continues living in the caller functions (those functions, -after finishing using the substring, must DECREF it). */ +#define FORMAT_BUFFER_SIZE 50 + Py_LOCAL_INLINE(int) -_ParseTupleFinds (PyObject *args, PyObject **substring, - Py_ssize_t *start, Py_ssize_t *end) { - PyObject *tmp_substring; +stringlib_parse_args_finds(const char * function_name, PyObject *args, + PyObject **subobj, + Py_ssize_t *start, Py_ssize_t *end) +{ + PyObject *tmp_subobj; Py_ssize_t tmp_start = 0; Py_ssize_t tmp_end = PY_SSIZE_T_MAX; PyObject *obj_start=Py_None, *obj_end=Py_None; + char format[FORMAT_BUFFER_SIZE] = "O|OO:"; + size_t len = strlen(format); - if (!PyArg_ParseTuple(args, "O|OO:find", &tmp_substring, - &obj_start, &obj_end)) + strncpy(format + len, function_name, FORMAT_BUFFER_SIZE - len - 1); + format[FORMAT_BUFFER_SIZE - 1] = '\0'; + + if (!PyArg_ParseTuple(args, format, &tmp_subobj, &obj_start, &obj_end)) return 0; /* To support None in "start" and "end" arguments, meaning @@ -131,16 +132,44 @@ if (!_PyEval_SliceIndex(obj_end, &tmp_end)) return 0; - tmp_substring = PyUnicode_FromObject(tmp_substring); - if (!tmp_substring) - return 0; - *start = tmp_start; *end = tmp_end; - *substring = tmp_substring; + *subobj = tmp_subobj; return 1; } +#undef FORMAT_BUFFER_SIZE + +#if STRINGLIB_IS_UNICODE + +/* +Wraps stringlib_parse_args_finds() and additionally ensures that the +first argument is a unicode object. + +Note that we receive a pointer to the pointer of the substring object, +so when we create that object in this function we don't DECREF it, +because it continues living in the caller functions (those functions, +after finishing using the substring, must DECREF it). +*/ + +Py_LOCAL_INLINE(int) +stringlib_parse_args_finds_unicode(const char * function_name, PyObject *args, + PyUnicodeObject **substring, + Py_ssize_t *start, Py_ssize_t *end) +{ + PyObject *tmp_substring; + + if(stringlib_parse_args_finds(function_name, args, &tmp_substring, + start, end)) { + tmp_substring = PyUnicode_FromObject(tmp_substring); + if (!tmp_substring) + return 0; + *substring = (PyUnicodeObject *)tmp_substring; + return 1; + } + return 0; +} + #endif /* STRINGLIB_IS_UNICODE */ #endif /* STRINGLIB_FIND_H */ diff --git a/Objects/stringobject.c b/Objects/stringobject.c --- a/Objects/stringobject.c +++ b/Objects/stringobject.c @@ -1693,19 +1693,9 @@ const char *sub; Py_ssize_t sub_len; Py_ssize_t start=0, end=PY_SSIZE_T_MAX; - PyObject *obj_start=Py_None, *obj_end=Py_None; - - if (!PyArg_ParseTuple(args, "O|OO:find/rfind/index/rindex", &subobj, - &obj_start, &obj_end)) - return -2; - /* To support None in "start" and "end" arguments, meaning - the same as if they were not passed. - */ - if (obj_start != Py_None) - if (!_PyEval_SliceIndex(obj_start, &start)) - return -2; - if (obj_end != Py_None) - if (!_PyEval_SliceIndex(obj_end, &end)) + + if (!stringlib_parse_args_finds("find/rfind/index/rindex", + args, &subobj, &start, &end)) return -2; if (PyString_Check(subobj)) { @@ -2117,8 +2107,7 @@ Py_ssize_t sub_len; Py_ssize_t start = 0, end = PY_SSIZE_T_MAX; - if (!PyArg_ParseTuple(args, "O|O&O&:count", &sub_obj, - _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) + if (!stringlib_parse_args_finds("count", args, &sub_obj, &start, &end)) return NULL; if (PyString_Check(sub_obj)) { @@ -2912,8 +2901,7 @@ PyObject *subobj; int result; - if (!PyArg_ParseTuple(args, "O|O&O&:startswith", &subobj, - _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) + if (!stringlib_parse_args_finds("startswith", args, &subobj, &start, &end)) return NULL; if (PyTuple_Check(subobj)) { Py_ssize_t i; @@ -2953,8 +2941,7 @@ PyObject *subobj; int result; - if (!PyArg_ParseTuple(args, "O|O&O&:endswith", &subobj, - _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) + if (!stringlib_parse_args_finds("endswith", args, &subobj, &start, &end)) return NULL; if (PyTuple_Check(subobj)) { Py_ssize_t i; diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -6308,13 +6308,8 @@ Py_ssize_t end = PY_SSIZE_T_MAX; PyObject *result; - if (!PyArg_ParseTuple(args, "O|O&O&:count", &substring, - _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) - return NULL; - - substring = (PyUnicodeObject *)PyUnicode_FromObject( - (PyObject *)substring); - if (substring == NULL) + if (!stringlib_parse_args_finds_unicode("count", args, &substring, + &start, &end)) return NULL; ADJUST_INDICES(start, end, self->length); @@ -6504,12 +6499,13 @@ static PyObject * unicode_find(PyUnicodeObject *self, PyObject *args) { - PyObject *substring; + PyUnicodeObject *substring; Py_ssize_t start; Py_ssize_t end; Py_ssize_t result; - if (!_ParseTupleFinds(args, &substring, &start, &end)) + if (!stringlib_parse_args_finds_unicode("find", args, &substring, + &start, &end)) return NULL; result = stringlib_find_slice( @@ -6570,11 +6566,12 @@ unicode_index(PyUnicodeObject *self, PyObject *args) { Py_ssize_t result; - PyObject *substring; + PyUnicodeObject *substring; Py_ssize_t start; Py_ssize_t end; - if (!_ParseTupleFinds(args, &substring, &start, &end)) + if (!stringlib_parse_args_finds_unicode("index", args, &substring, + &start, &end)) return NULL; result = stringlib_find_slice( @@ -7237,12 +7234,13 @@ static PyObject * unicode_rfind(PyUnicodeObject *self, PyObject *args) { - PyObject *substring; + PyUnicodeObject *substring; Py_ssize_t start; Py_ssize_t end; Py_ssize_t result; - if (!_ParseTupleFinds(args, &substring, &start, &end)) + if (!stringlib_parse_args_finds_unicode("rfind", args, &substring, + &start, &end)) return NULL; result = stringlib_rfind_slice( @@ -7264,12 +7262,13 @@ static PyObject * unicode_rindex(PyUnicodeObject *self, PyObject *args) { - PyObject *substring; + PyUnicodeObject *substring; Py_ssize_t start; Py_ssize_t end; Py_ssize_t result; - if (!_ParseTupleFinds(args, &substring, &start, &end)) + if (!stringlib_parse_args_finds_unicode("rindex", args, &substring, + &start, &end)) return NULL; result = stringlib_rfind_slice( @@ -7648,8 +7647,7 @@ Py_ssize_t end = PY_SSIZE_T_MAX; int result; - if (!PyArg_ParseTuple(args, "O|O&O&:startswith", &subobj, - _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) + if (!stringlib_parse_args_finds("startswith", args, &subobj, &start, &end)) return NULL; if (PyTuple_Check(subobj)) { Py_ssize_t i; @@ -7694,8 +7692,7 @@ Py_ssize_t end = PY_SSIZE_T_MAX; int result; - if (!PyArg_ParseTuple(args, "O|O&O&:endswith", &subobj, - _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) + if (!stringlib_parse_args_finds("endswith", args, &subobj, &start, &end)) return NULL; if (PyTuple_Check(subobj)) { Py_ssize_t i; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 20 17:59:52 2011 From: python-checkins at python.org (jesus.cea) Date: Wed, 20 Apr 2011 17:59:52 +0200 Subject: [Python-checkins] cpython (3.1): startswith and endswith don't accept None as slice index. Patch by Torsten Message-ID: http://hg.python.org/cpython/rev/77c657e47b5c changeset: 69472:77c657e47b5c branch: 3.1 parent: 69460:408f23b6cec5 user: Jesus Cea date: Wed Apr 20 17:09:23 2011 +0200 summary: startswith and endswith don't accept None as slice index. Patch by Torsten Becker. (closes #11828) files: Lib/test/string_tests.py | 57 ++++++++++++++++++++++ Lib/test/test_bytes.py | 62 ++++++++++++++++++++++++ Misc/ACKS | 1 + Misc/NEWS | 3 + Objects/bytearrayobject.c | 13 ++--- Objects/bytesobject.c | 25 ++------- Objects/stringlib/find.h | 67 +++++++++++++++++++------- Objects/unicodeobject.c | 35 ++++++------- 8 files changed, 198 insertions(+), 65 deletions(-) diff --git a/Lib/test/string_tests.py b/Lib/test/string_tests.py --- a/Lib/test/string_tests.py +++ b/Lib/test/string_tests.py @@ -1156,6 +1156,63 @@ self.checkraises(ValueError, S, 'rpartition', '') self.checkraises(TypeError, S, 'rpartition', None) + def test_none_arguments(self): + # issue 11828 + s = 'hello' + self.checkequal(2, s, 'find', 'l', None) + self.checkequal(3, s, 'find', 'l', -2, None) + self.checkequal(2, s, 'find', 'l', None, -2) + self.checkequal(0, s, 'find', 'h', None, None) + + self.checkequal(3, s, 'rfind', 'l', None) + self.checkequal(3, s, 'rfind', 'l', -2, None) + self.checkequal(2, s, 'rfind', 'l', None, -2) + self.checkequal(0, s, 'rfind', 'h', None, None) + + self.checkequal(2, s, 'index', 'l', None) + self.checkequal(3, s, 'index', 'l', -2, None) + self.checkequal(2, s, 'index', 'l', None, -2) + self.checkequal(0, s, 'index', 'h', None, None) + + self.checkequal(3, s, 'rindex', 'l', None) + self.checkequal(3, s, 'rindex', 'l', -2, None) + self.checkequal(2, s, 'rindex', 'l', None, -2) + self.checkequal(0, s, 'rindex', 'h', None, None) + + self.checkequal(2, s, 'count', 'l', None) + self.checkequal(1, s, 'count', 'l', -2, None) + self.checkequal(1, s, 'count', 'l', None, -2) + self.checkequal(0, s, 'count', 'x', None, None) + + self.checkequal(True, s, 'endswith', 'o', None) + self.checkequal(True, s, 'endswith', 'lo', -2, None) + self.checkequal(True, s, 'endswith', 'l', None, -2) + self.checkequal(False, s, 'endswith', 'x', None, None) + + self.checkequal(True, s, 'startswith', 'h', None) + self.checkequal(True, s, 'startswith', 'l', -2, None) + self.checkequal(True, s, 'startswith', 'h', None, -2) + self.checkequal(False, s, 'startswith', 'x', None, None) + + def test_find_etc_raise_correct_error_messages(self): + # issue 11828 + s = 'hello' + x = 'x' + self.assertRaisesRegexp(TypeError, r'^find\(', s.find, + x, None, None, None) + self.assertRaisesRegexp(TypeError, r'^rfind\(', s.rfind, + x, None, None, None) + self.assertRaisesRegexp(TypeError, r'^index\(', s.index, + x, None, None, None) + self.assertRaisesRegexp(TypeError, r'^rindex\(', s.rindex, + x, None, None, None) + self.assertRaisesRegexp(TypeError, r'^count\(', s.count, + x, None, None, None) + self.assertRaisesRegexp(TypeError, r'^startswith\(', s.startswith, + x, None, None, None) + self.assertRaisesRegexp(TypeError, r'^endswith\(', s.endswith, + x, None, None, None) + class MixinStrUnicodeTest: # Additional tests that only work with str and unicode. 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 @@ -459,6 +459,68 @@ self.assertRaises(ValueError, self.type2test.maketrans, b'abc', b'xyzq') self.assertRaises(TypeError, self.type2test.maketrans, 'abc', 'def') + def test_none_arguments(self): + # issue 11828 + b = self.type2test(b'hello') + l = self.type2test(b'l') + h = self.type2test(b'h') + x = self.type2test(b'x') + o = self.type2test(b'o') + + self.assertEqual(2, b.find(l, None)) + self.assertEqual(3, b.find(l, -2, None)) + self.assertEqual(2, b.find(l, None, -2)) + self.assertEqual(0, b.find(h, None, None)) + + self.assertEqual(3, b.rfind(l, None)) + self.assertEqual(3, b.rfind(l, -2, None)) + self.assertEqual(2, b.rfind(l, None, -2)) + self.assertEqual(0, b.rfind(h, None, None)) + + self.assertEqual(2, b.index(l, None)) + self.assertEqual(3, b.index(l, -2, None)) + self.assertEqual(2, b.index(l, None, -2)) + self.assertEqual(0, b.index(h, None, None)) + + self.assertEqual(3, b.rindex(l, None)) + self.assertEqual(3, b.rindex(l, -2, None)) + self.assertEqual(2, b.rindex(l, None, -2)) + self.assertEqual(0, b.rindex(h, None, None)) + + self.assertEqual(2, b.count(l, None)) + self.assertEqual(1, b.count(l, -2, None)) + self.assertEqual(1, b.count(l, None, -2)) + self.assertEqual(0, b.count(x, None, None)) + + self.assertEqual(True, b.endswith(o, None)) + self.assertEqual(True, b.endswith(o, -2, None)) + self.assertEqual(True, b.endswith(l, None, -2)) + self.assertEqual(False, b.endswith(x, None, None)) + + self.assertEqual(True, b.startswith(h, None)) + self.assertEqual(True, b.startswith(l, -2, None)) + self.assertEqual(True, b.startswith(h, None, -2)) + self.assertEqual(False, b.startswith(x, None, None)) + + def test_find_etc_raise_correct_error_messages(self): + # issue 11828 + b = self.type2test(b'hello') + x = self.type2test(b'x') + self.assertRaisesRegexp(TypeError, r'\bfind\b', b.find, + x, None, None, None) + self.assertRaisesRegexp(TypeError, r'\brfind\b', b.rfind, + x, None, None, None) + self.assertRaisesRegexp(TypeError, r'\bindex\b', b.index, + x, None, None, None) + self.assertRaisesRegexp(TypeError, r'\brindex\b', b.rindex, + x, None, None, None) + self.assertRaisesRegexp(TypeError, r'\bcount\b', b.count, + x, None, None, None) + self.assertRaisesRegexp(TypeError, r'\bstartswith\b', b.startswith, + x, None, None, None) + self.assertRaisesRegexp(TypeError, r'\bendswith\b', b.endswith, + x, None, None, None) + class BytesTest(BaseBytesTest): type2test = bytes diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -58,6 +58,7 @@ David Beazley Robin Becker Neal Becker +Torsten Becker Bill Bedford Stefan Behnel Reimer Behrends diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -38,6 +38,9 @@ - Issue #8278: On Windows and with a NTFS filesystem, os.stat() and os.utime() can now handle dates after 2038. +- issue #11828: startswith and endswith don't accept None as slice index. + Patch by Torsten Becker. + - Issue #4236: PyModule_Create2 now checks the import machinery directly rather than the Py_IsInitialized flag, avoiding a Fatal Python error in certain circumstances when an import is done in __del__. diff --git a/Objects/bytearrayobject.c b/Objects/bytearrayobject.c --- a/Objects/bytearrayobject.c +++ b/Objects/bytearrayobject.c @@ -1082,8 +1082,8 @@ Py_ssize_t start=0, end=PY_SSIZE_T_MAX; Py_ssize_t res; - if (!PyArg_ParseTuple(args, "O|O&O&:find/rfind/index/rindex", &subobj, - _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) + if (!stringlib_parse_args_finds("find/rfind/index/rindex", + args, &subobj, &start, &end)) return -2; if (_getbuffer(subobj, &subbuf) < 0) return -2; @@ -1133,8 +1133,7 @@ Py_buffer vsub; PyObject *count_obj; - if (!PyArg_ParseTuple(args, "O|O&O&:count", &sub_obj, - _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) + if (!stringlib_parse_args_finds("count", args, &sub_obj, &start, &end)) return NULL; if (_getbuffer(sub_obj, &vsub) < 0) @@ -1292,8 +1291,7 @@ PyObject *subobj; int result; - if (!PyArg_ParseTuple(args, "O|O&O&:startswith", &subobj, - _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) + if (!stringlib_parse_args_finds("startswith", args, &subobj, &start, &end)) return NULL; if (PyTuple_Check(subobj)) { Py_ssize_t i; @@ -1332,8 +1330,7 @@ PyObject *subobj; int result; - if (!PyArg_ParseTuple(args, "O|O&O&:endswith", &subobj, - _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) + if (!stringlib_parse_args_finds("endswith", args, &subobj, &start, &end)) return NULL; if (PyTuple_Check(subobj)) { Py_ssize_t i; diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -1567,19 +1567,9 @@ const char *sub; Py_ssize_t sub_len; Py_ssize_t start=0, end=PY_SSIZE_T_MAX; - PyObject *obj_start=Py_None, *obj_end=Py_None; - - if (!PyArg_ParseTuple(args, "O|OO:find/rfind/index/rindex", &subobj, - &obj_start, &obj_end)) - return -2; - /* To support None in "start" and "end" arguments, meaning - the same as if they were not passed. - */ - if (obj_start != Py_None) - if (!_PyEval_SliceIndex(obj_start, &start)) - return -2; - if (obj_end != Py_None) - if (!_PyEval_SliceIndex(obj_end, &end)) + + if (!stringlib_parse_args_finds("find/rfind/index/rindex", + args, &subobj, &start, &end)) return -2; if (PyBytes_Check(subobj)) { @@ -1826,8 +1816,7 @@ Py_ssize_t sub_len; Py_ssize_t start = 0, end = PY_SSIZE_T_MAX; - if (!PyArg_ParseTuple(args, "O|O&O&:count", &sub_obj, - _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) + if (!stringlib_parse_args_finds("count", args, &sub_obj, &start, &end)) return NULL; if (PyBytes_Check(sub_obj)) { @@ -2648,8 +2637,7 @@ PyObject *subobj; int result; - if (!PyArg_ParseTuple(args, "O|O&O&:startswith", &subobj, - _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) + if (!stringlib_parse_args_finds("startswith", args, &subobj, &start, &end)) return NULL; if (PyTuple_Check(subobj)) { Py_ssize_t i; @@ -2689,8 +2677,7 @@ PyObject *subobj; int result; - if (!PyArg_ParseTuple(args, "O|O&O&:endswith", &subobj, - _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) + if (!stringlib_parse_args_finds("endswith", args, &subobj, &start, &end)) return NULL; if (PyTuple_Check(subobj)) { Py_ssize_t i; diff --git a/Objects/stringlib/find.h b/Objects/stringlib/find.h --- a/Objects/stringlib/find.h +++ b/Objects/stringlib/find.h @@ -102,32 +102,33 @@ #endif /* STRINGLIB_STR */ -#ifdef FROM_UNICODE - /* This function is a helper for the "find" family (find, rfind, index, -rindex) of unicodeobject.c file, because they all have the same -behaviour for the arguments. +rindex) and for count, startswith and endswith, because they all have +the same behaviour for the arguments. It does not touch the variables received until it knows everything is ok. - -Note that we receive a pointer to the pointer of the substring object, -so when we create that object in this function we don't DECREF it, -because it continues living in the caller functions (those functions, -after finishing using the substring, must DECREF it). */ +#define FORMAT_BUFFER_SIZE 50 + Py_LOCAL_INLINE(int) -_ParseTupleFinds (PyObject *args, PyObject **substring, - Py_ssize_t *start, Py_ssize_t *end) { - PyObject *tmp_substring; +stringlib_parse_args_finds(const char * function_name, PyObject *args, + PyObject **subobj, + Py_ssize_t *start, Py_ssize_t *end) +{ + PyObject *tmp_subobj; Py_ssize_t tmp_start = 0; Py_ssize_t tmp_end = PY_SSIZE_T_MAX; PyObject *obj_start=Py_None, *obj_end=Py_None; + char format[FORMAT_BUFFER_SIZE] = "O|OO:"; + size_t len = strlen(format); - if (!PyArg_ParseTuple(args, "O|OO:find", &tmp_substring, - &obj_start, &obj_end)) + strncpy(format + len, function_name, FORMAT_BUFFER_SIZE - len - 1); + format[FORMAT_BUFFER_SIZE - 1] = '\0'; + + if (!PyArg_ParseTuple(args, format, &tmp_subobj, &obj_start, &obj_end)) return 0; /* To support None in "start" and "end" arguments, meaning @@ -140,16 +141,44 @@ if (!_PyEval_SliceIndex(obj_end, &tmp_end)) return 0; - tmp_substring = PyUnicode_FromObject(tmp_substring); - if (!tmp_substring) - return 0; - *start = tmp_start; *end = tmp_end; - *substring = tmp_substring; + *subobj = tmp_subobj; return 1; } +#undef FORMAT_BUFFER_SIZE + +#ifdef FROM_UNICODE + +/* +Wraps stringlib_parse_args_finds() and additionally ensures that the +first argument is a unicode object. + +Note that we receive a pointer to the pointer of the substring object, +so when we create that object in this function we don't DECREF it, +because it continues living in the caller functions (those functions, +after finishing using the substring, must DECREF it). +*/ + +Py_LOCAL_INLINE(int) +stringlib_parse_args_finds_unicode(const char * function_name, PyObject *args, + PyUnicodeObject **substring, + Py_ssize_t *start, Py_ssize_t *end) +{ + PyObject *tmp_substring; + + if(stringlib_parse_args_finds(function_name, args, &tmp_substring, + start, end)) { + tmp_substring = PyUnicode_FromObject(tmp_substring); + if (!tmp_substring) + return 0; + *substring = (PyUnicodeObject *)tmp_substring; + return 1; + } + return 0; +} + #endif /* FROM_UNICODE */ #endif /* STRINGLIB_FIND_H */ diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -7150,13 +7150,8 @@ Py_ssize_t end = PY_SSIZE_T_MAX; PyObject *result; - if (!PyArg_ParseTuple(args, "O|O&O&:count", &substring, - _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) - return NULL; - - substring = (PyUnicodeObject *)PyUnicode_FromObject( - (PyObject *)substring); - if (substring == NULL) + if (!stringlib_parse_args_finds_unicode("count", args, &substring, + &start, &end)) return NULL; FIX_START_END(self); @@ -7306,12 +7301,13 @@ static PyObject * unicode_find(PyUnicodeObject *self, PyObject *args) { - PyObject *substring; + PyUnicodeObject *substring; Py_ssize_t start; Py_ssize_t end; Py_ssize_t result; - if (!_ParseTupleFinds(args, &substring, &start, &end)) + if (!stringlib_parse_args_finds_unicode("find", args, &substring, + &start, &end)) return NULL; result = stringlib_find_slice( @@ -7368,11 +7364,12 @@ unicode_index(PyUnicodeObject *self, PyObject *args) { Py_ssize_t result; - PyObject *substring; + PyUnicodeObject *substring; Py_ssize_t start; Py_ssize_t end; - if (!_ParseTupleFinds(args, &substring, &start, &end)) + if (!stringlib_parse_args_finds_unicode("index", args, &substring, + &start, &end)) return NULL; result = stringlib_find_slice( @@ -8230,12 +8227,13 @@ static PyObject * unicode_rfind(PyUnicodeObject *self, PyObject *args) { - PyObject *substring; + PyUnicodeObject *substring; Py_ssize_t start; Py_ssize_t end; Py_ssize_t result; - if (!_ParseTupleFinds(args, &substring, &start, &end)) + if (!stringlib_parse_args_finds_unicode("rfind", args, &substring, + &start, &end)) return NULL; result = stringlib_rfind_slice( @@ -8257,12 +8255,13 @@ static PyObject * unicode_rindex(PyUnicodeObject *self, PyObject *args) { - PyObject *substring; + PyUnicodeObject *substring; Py_ssize_t start; Py_ssize_t end; Py_ssize_t result; - if (!_ParseTupleFinds(args, &substring, &start, &end)) + if (!stringlib_parse_args_finds_unicode("rindex", args, &substring, + &start, &end)) return NULL; result = stringlib_rfind_slice( @@ -8725,8 +8724,7 @@ Py_ssize_t end = PY_SSIZE_T_MAX; int result; - if (!PyArg_ParseTuple(args, "O|O&O&:startswith", &subobj, - _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) + if (!stringlib_parse_args_finds("startswith", args, &subobj, &start, &end)) return NULL; if (PyTuple_Check(subobj)) { Py_ssize_t i; @@ -8771,8 +8769,7 @@ Py_ssize_t end = PY_SSIZE_T_MAX; int result; - if (!PyArg_ParseTuple(args, "O|O&O&:endswith", &subobj, - _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) + if (!stringlib_parse_args_finds("endswith", args, &subobj, &start, &end)) return NULL; if (PyTuple_Check(subobj)) { Py_ssize_t i; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 20 17:59:55 2011 From: python-checkins at python.org (jesus.cea) Date: Wed, 20 Apr 2011 17:59:55 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): MERGE: startswith and endswith don't accept None as slice index. Patch by Message-ID: http://hg.python.org/cpython/rev/e5f11efe89a6 changeset: 69473:e5f11efe89a6 branch: 3.2 parent: 69461:4e6840477d96 parent: 69472:77c657e47b5c user: Jesus Cea date: Wed Apr 20 17:42:50 2011 +0200 summary: MERGE: startswith and endswith don't accept None as slice index. Patch by Torsten Becker. (closes #11828) files: Lib/test/string_tests.py | 57 ++++++++++++++++++++++ Lib/test/test_bytes.py | 62 ++++++++++++++++++++++++ Misc/ACKS | 1 + Misc/NEWS | 3 + Objects/bytearrayobject.c | 13 ++--- Objects/bytesobject.c | 25 ++------- Objects/stringlib/find.h | 67 +++++++++++++++++++------- Objects/unicodeobject.c | 35 ++++++------- 8 files changed, 198 insertions(+), 65 deletions(-) diff --git a/Lib/test/string_tests.py b/Lib/test/string_tests.py --- a/Lib/test/string_tests.py +++ b/Lib/test/string_tests.py @@ -1183,6 +1183,63 @@ self.checkraises(ValueError, S, 'rpartition', '') self.checkraises(TypeError, S, 'rpartition', None) + def test_none_arguments(self): + # issue 11828 + s = 'hello' + self.checkequal(2, s, 'find', 'l', None) + self.checkequal(3, s, 'find', 'l', -2, None) + self.checkequal(2, s, 'find', 'l', None, -2) + self.checkequal(0, s, 'find', 'h', None, None) + + self.checkequal(3, s, 'rfind', 'l', None) + self.checkequal(3, s, 'rfind', 'l', -2, None) + self.checkequal(2, s, 'rfind', 'l', None, -2) + self.checkequal(0, s, 'rfind', 'h', None, None) + + self.checkequal(2, s, 'index', 'l', None) + self.checkequal(3, s, 'index', 'l', -2, None) + self.checkequal(2, s, 'index', 'l', None, -2) + self.checkequal(0, s, 'index', 'h', None, None) + + self.checkequal(3, s, 'rindex', 'l', None) + self.checkequal(3, s, 'rindex', 'l', -2, None) + self.checkequal(2, s, 'rindex', 'l', None, -2) + self.checkequal(0, s, 'rindex', 'h', None, None) + + self.checkequal(2, s, 'count', 'l', None) + self.checkequal(1, s, 'count', 'l', -2, None) + self.checkequal(1, s, 'count', 'l', None, -2) + self.checkequal(0, s, 'count', 'x', None, None) + + self.checkequal(True, s, 'endswith', 'o', None) + self.checkequal(True, s, 'endswith', 'lo', -2, None) + self.checkequal(True, s, 'endswith', 'l', None, -2) + self.checkequal(False, s, 'endswith', 'x', None, None) + + self.checkequal(True, s, 'startswith', 'h', None) + self.checkequal(True, s, 'startswith', 'l', -2, None) + self.checkequal(True, s, 'startswith', 'h', None, -2) + self.checkequal(False, s, 'startswith', 'x', None, None) + + def test_find_etc_raise_correct_error_messages(self): + # issue 11828 + s = 'hello' + x = 'x' + self.assertRaisesRegexp(TypeError, r'^find\(', s.find, + x, None, None, None) + self.assertRaisesRegexp(TypeError, r'^rfind\(', s.rfind, + x, None, None, None) + self.assertRaisesRegexp(TypeError, r'^index\(', s.index, + x, None, None, None) + self.assertRaisesRegexp(TypeError, r'^rindex\(', s.rindex, + x, None, None, None) + self.assertRaisesRegexp(TypeError, r'^count\(', s.count, + x, None, None, None) + self.assertRaisesRegexp(TypeError, r'^startswith\(', s.startswith, + x, None, None, None) + self.assertRaisesRegexp(TypeError, r'^endswith\(', s.endswith, + x, None, None, None) + class MixinStrUnicodeTest: # Additional tests that only work with str and unicode. 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 @@ -476,6 +476,68 @@ self.assertRaises(ValueError, self.type2test.maketrans, b'abc', b'xyzq') self.assertRaises(TypeError, self.type2test.maketrans, 'abc', 'def') + def test_none_arguments(self): + # issue 11828 + b = self.type2test(b'hello') + l = self.type2test(b'l') + h = self.type2test(b'h') + x = self.type2test(b'x') + o = self.type2test(b'o') + + self.assertEqual(2, b.find(l, None)) + self.assertEqual(3, b.find(l, -2, None)) + self.assertEqual(2, b.find(l, None, -2)) + self.assertEqual(0, b.find(h, None, None)) + + self.assertEqual(3, b.rfind(l, None)) + self.assertEqual(3, b.rfind(l, -2, None)) + self.assertEqual(2, b.rfind(l, None, -2)) + self.assertEqual(0, b.rfind(h, None, None)) + + self.assertEqual(2, b.index(l, None)) + self.assertEqual(3, b.index(l, -2, None)) + self.assertEqual(2, b.index(l, None, -2)) + self.assertEqual(0, b.index(h, None, None)) + + self.assertEqual(3, b.rindex(l, None)) + self.assertEqual(3, b.rindex(l, -2, None)) + self.assertEqual(2, b.rindex(l, None, -2)) + self.assertEqual(0, b.rindex(h, None, None)) + + self.assertEqual(2, b.count(l, None)) + self.assertEqual(1, b.count(l, -2, None)) + self.assertEqual(1, b.count(l, None, -2)) + self.assertEqual(0, b.count(x, None, None)) + + self.assertEqual(True, b.endswith(o, None)) + self.assertEqual(True, b.endswith(o, -2, None)) + self.assertEqual(True, b.endswith(l, None, -2)) + self.assertEqual(False, b.endswith(x, None, None)) + + self.assertEqual(True, b.startswith(h, None)) + self.assertEqual(True, b.startswith(l, -2, None)) + self.assertEqual(True, b.startswith(h, None, -2)) + self.assertEqual(False, b.startswith(x, None, None)) + + def test_find_etc_raise_correct_error_messages(self): + # issue 11828 + b = self.type2test(b'hello') + x = self.type2test(b'x') + self.assertRaisesRegexp(TypeError, r'\bfind\b', b.find, + x, None, None, None) + self.assertRaisesRegexp(TypeError, r'\brfind\b', b.rfind, + x, None, None, None) + self.assertRaisesRegexp(TypeError, r'\bindex\b', b.index, + x, None, None, None) + self.assertRaisesRegexp(TypeError, r'\brindex\b', b.rindex, + x, None, None, None) + self.assertRaisesRegexp(TypeError, r'\bcount\b', b.count, + x, None, None, None) + self.assertRaisesRegexp(TypeError, r'\bstartswith\b', b.startswith, + x, None, None, None) + self.assertRaisesRegexp(TypeError, r'\bendswith\b', b.endswith, + x, None, None, None) + class BytesTest(BaseBytesTest): type2test = bytes diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -66,6 +66,7 @@ David Beazley Robin Becker Neal Becker +Torsten Becker Bill Bedford Stefan Behnel Reimer Behrends diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -49,6 +49,9 @@ - Issue #11272: On Windows, input() strips '\r' (and not only '\n'), and sys.stdin uses universal newline (replace '\r\n' by '\n'). +- issue #11828: startswith and endswith don't accept None as slice index. + Patch by Torsten Becker. + - Issue #10830: Fix PyUnicode_FromFormatV("%c") for non-BMP characters on narrow build. diff --git a/Objects/bytearrayobject.c b/Objects/bytearrayobject.c --- a/Objects/bytearrayobject.c +++ b/Objects/bytearrayobject.c @@ -1081,8 +1081,8 @@ Py_ssize_t start=0, end=PY_SSIZE_T_MAX; Py_ssize_t res; - if (!PyArg_ParseTuple(args, "O|O&O&:find/rfind/index/rindex", &subobj, - _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) + if (!stringlib_parse_args_finds("find/rfind/index/rindex", + args, &subobj, &start, &end)) return -2; if (_getbuffer(subobj, &subbuf) < 0) return -2; @@ -1132,8 +1132,7 @@ Py_buffer vsub; PyObject *count_obj; - if (!PyArg_ParseTuple(args, "O|O&O&:count", &sub_obj, - _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) + if (!stringlib_parse_args_finds("count", args, &sub_obj, &start, &end)) return NULL; if (_getbuffer(sub_obj, &vsub) < 0) @@ -1291,8 +1290,7 @@ PyObject *subobj; int result; - if (!PyArg_ParseTuple(args, "O|O&O&:startswith", &subobj, - _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) + if (!stringlib_parse_args_finds("startswith", args, &subobj, &start, &end)) return NULL; if (PyTuple_Check(subobj)) { Py_ssize_t i; @@ -1331,8 +1329,7 @@ PyObject *subobj; int result; - if (!PyArg_ParseTuple(args, "O|O&O&:endswith", &subobj, - _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) + if (!stringlib_parse_args_finds("endswith", args, &subobj, &start, &end)) return NULL; if (PyTuple_Check(subobj)) { Py_ssize_t i; diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -1244,19 +1244,9 @@ const char *sub; Py_ssize_t sub_len; Py_ssize_t start=0, end=PY_SSIZE_T_MAX; - PyObject *obj_start=Py_None, *obj_end=Py_None; - - if (!PyArg_ParseTuple(args, "O|OO:find/rfind/index/rindex", &subobj, - &obj_start, &obj_end)) - return -2; - /* To support None in "start" and "end" arguments, meaning - the same as if they were not passed. - */ - if (obj_start != Py_None) - if (!_PyEval_SliceIndex(obj_start, &start)) - return -2; - if (obj_end != Py_None) - if (!_PyEval_SliceIndex(obj_end, &end)) + + if (!stringlib_parse_args_finds("find/rfind/index/rindex", + args, &subobj, &start, &end)) return -2; if (PyBytes_Check(subobj)) { @@ -1503,8 +1493,7 @@ Py_ssize_t sub_len; Py_ssize_t start = 0, end = PY_SSIZE_T_MAX; - if (!PyArg_ParseTuple(args, "O|O&O&:count", &sub_obj, - _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) + if (!stringlib_parse_args_finds("count", args, &sub_obj, &start, &end)) return NULL; if (PyBytes_Check(sub_obj)) { @@ -2222,8 +2211,7 @@ PyObject *subobj; int result; - if (!PyArg_ParseTuple(args, "O|O&O&:startswith", &subobj, - _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) + if (!stringlib_parse_args_finds("startswith", args, &subobj, &start, &end)) return NULL; if (PyTuple_Check(subobj)) { Py_ssize_t i; @@ -2263,8 +2251,7 @@ PyObject *subobj; int result; - if (!PyArg_ParseTuple(args, "O|O&O&:endswith", &subobj, - _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) + if (!stringlib_parse_args_finds("endswith", args, &subobj, &start, &end)) return NULL; if (PyTuple_Check(subobj)) { Py_ssize_t i; diff --git a/Objects/stringlib/find.h b/Objects/stringlib/find.h --- a/Objects/stringlib/find.h +++ b/Objects/stringlib/find.h @@ -93,32 +93,33 @@ #endif /* STRINGLIB_WANT_CONTAINS_OBJ */ -#if STRINGLIB_IS_UNICODE - /* This function is a helper for the "find" family (find, rfind, index, -rindex) of unicodeobject.c file, because they all have the same -behaviour for the arguments. +rindex) and for count, startswith and endswith, because they all have +the same behaviour for the arguments. It does not touch the variables received until it knows everything is ok. - -Note that we receive a pointer to the pointer of the substring object, -so when we create that object in this function we don't DECREF it, -because it continues living in the caller functions (those functions, -after finishing using the substring, must DECREF it). */ +#define FORMAT_BUFFER_SIZE 50 + Py_LOCAL_INLINE(int) -_ParseTupleFinds (PyObject *args, PyObject **substring, - Py_ssize_t *start, Py_ssize_t *end) { - PyObject *tmp_substring; +stringlib_parse_args_finds(const char * function_name, PyObject *args, + PyObject **subobj, + Py_ssize_t *start, Py_ssize_t *end) +{ + PyObject *tmp_subobj; Py_ssize_t tmp_start = 0; Py_ssize_t tmp_end = PY_SSIZE_T_MAX; PyObject *obj_start=Py_None, *obj_end=Py_None; + char format[FORMAT_BUFFER_SIZE] = "O|OO:"; + size_t len = strlen(format); - if (!PyArg_ParseTuple(args, "O|OO:find", &tmp_substring, - &obj_start, &obj_end)) + strncpy(format + len, function_name, FORMAT_BUFFER_SIZE - len - 1); + format[FORMAT_BUFFER_SIZE - 1] = '\0'; + + if (!PyArg_ParseTuple(args, format, &tmp_subobj, &obj_start, &obj_end)) return 0; /* To support None in "start" and "end" arguments, meaning @@ -131,16 +132,44 @@ if (!_PyEval_SliceIndex(obj_end, &tmp_end)) return 0; - tmp_substring = PyUnicode_FromObject(tmp_substring); - if (!tmp_substring) - return 0; - *start = tmp_start; *end = tmp_end; - *substring = tmp_substring; + *subobj = tmp_subobj; return 1; } +#undef FORMAT_BUFFER_SIZE + +#if STRINGLIB_IS_UNICODE + +/* +Wraps stringlib_parse_args_finds() and additionally ensures that the +first argument is a unicode object. + +Note that we receive a pointer to the pointer of the substring object, +so when we create that object in this function we don't DECREF it, +because it continues living in the caller functions (those functions, +after finishing using the substring, must DECREF it). +*/ + +Py_LOCAL_INLINE(int) +stringlib_parse_args_finds_unicode(const char * function_name, PyObject *args, + PyUnicodeObject **substring, + Py_ssize_t *start, Py_ssize_t *end) +{ + PyObject *tmp_substring; + + if(stringlib_parse_args_finds(function_name, args, &tmp_substring, + start, end)) { + tmp_substring = PyUnicode_FromObject(tmp_substring); + if (!tmp_substring) + return 0; + *substring = (PyUnicodeObject *)tmp_substring; + return 1; + } + return 0; +} + #endif /* STRINGLIB_IS_UNICODE */ #endif /* STRINGLIB_FIND_H */ diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -7442,13 +7442,8 @@ Py_ssize_t end = PY_SSIZE_T_MAX; PyObject *result; - if (!PyArg_ParseTuple(args, "O|O&O&:count", &substring, - _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) - return NULL; - - substring = (PyUnicodeObject *)PyUnicode_FromObject( - (PyObject *)substring); - if (substring == NULL) + if (!stringlib_parse_args_finds_unicode("count", args, &substring, + &start, &end)) return NULL; ADJUST_INDICES(start, end, self->length); @@ -7585,12 +7580,13 @@ static PyObject * unicode_find(PyUnicodeObject *self, PyObject *args) { - PyObject *substring; + PyUnicodeObject *substring; Py_ssize_t start; Py_ssize_t end; Py_ssize_t result; - if (!_ParseTupleFinds(args, &substring, &start, &end)) + if (!stringlib_parse_args_finds_unicode("find", args, &substring, + &start, &end)) return NULL; result = stringlib_find_slice( @@ -7647,11 +7643,12 @@ unicode_index(PyUnicodeObject *self, PyObject *args) { Py_ssize_t result; - PyObject *substring; + PyUnicodeObject *substring; Py_ssize_t start; Py_ssize_t end; - if (!_ParseTupleFinds(args, &substring, &start, &end)) + if (!stringlib_parse_args_finds_unicode("index", args, &substring, + &start, &end)) return NULL; result = stringlib_find_slice( @@ -8509,12 +8506,13 @@ static PyObject * unicode_rfind(PyUnicodeObject *self, PyObject *args) { - PyObject *substring; + PyUnicodeObject *substring; Py_ssize_t start; Py_ssize_t end; Py_ssize_t result; - if (!_ParseTupleFinds(args, &substring, &start, &end)) + if (!stringlib_parse_args_finds_unicode("rfind", args, &substring, + &start, &end)) return NULL; result = stringlib_rfind_slice( @@ -8536,12 +8534,13 @@ static PyObject * unicode_rindex(PyUnicodeObject *self, PyObject *args) { - PyObject *substring; + PyUnicodeObject *substring; Py_ssize_t start; Py_ssize_t end; Py_ssize_t result; - if (!_ParseTupleFinds(args, &substring, &start, &end)) + if (!stringlib_parse_args_finds_unicode("rindex", args, &substring, + &start, &end)) return NULL; result = stringlib_rfind_slice( @@ -9011,8 +9010,7 @@ Py_ssize_t end = PY_SSIZE_T_MAX; int result; - if (!PyArg_ParseTuple(args, "O|O&O&:startswith", &subobj, - _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) + if (!stringlib_parse_args_finds("startswith", args, &subobj, &start, &end)) return NULL; if (PyTuple_Check(subobj)) { Py_ssize_t i; @@ -9057,8 +9055,7 @@ Py_ssize_t end = PY_SSIZE_T_MAX; int result; - if (!PyArg_ParseTuple(args, "O|O&O&:endswith", &subobj, - _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) + if (!stringlib_parse_args_finds("endswith", args, &subobj, &start, &end)) return NULL; if (PyTuple_Check(subobj)) { Py_ssize_t i; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 20 17:59:57 2011 From: python-checkins at python.org (jesus.cea) Date: Wed, 20 Apr 2011 17:59:57 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): MERGE: startswith and endswith don't accept None as slice index. Patch by Message-ID: http://hg.python.org/cpython/rev/b8d1cf9fde04 changeset: 69474:b8d1cf9fde04 parent: 69470:dd8d999713f4 parent: 69473:e5f11efe89a6 user: Jesus Cea date: Wed Apr 20 17:59:29 2011 +0200 summary: MERGE: startswith and endswith don't accept None as slice index. Patch by Torsten Becker. (closes #11828) files: Lib/test/string_tests.py | 57 ++++++++++++++++++++++ Lib/test/test_bytes.py | 62 ++++++++++++++++++++++++ Misc/ACKS | 1 + Misc/NEWS | 3 + Objects/bytearrayobject.c | 13 ++--- Objects/bytesobject.c | 25 ++------- Objects/stringlib/find.h | 67 +++++++++++++++++++------- Objects/unicodeobject.c | 35 ++++++------- 8 files changed, 198 insertions(+), 65 deletions(-) diff --git a/Lib/test/string_tests.py b/Lib/test/string_tests.py --- a/Lib/test/string_tests.py +++ b/Lib/test/string_tests.py @@ -1183,6 +1183,63 @@ self.checkraises(ValueError, S, 'rpartition', '') self.checkraises(TypeError, S, 'rpartition', None) + def test_none_arguments(self): + # issue 11828 + s = 'hello' + self.checkequal(2, s, 'find', 'l', None) + self.checkequal(3, s, 'find', 'l', -2, None) + self.checkequal(2, s, 'find', 'l', None, -2) + self.checkequal(0, s, 'find', 'h', None, None) + + self.checkequal(3, s, 'rfind', 'l', None) + self.checkequal(3, s, 'rfind', 'l', -2, None) + self.checkequal(2, s, 'rfind', 'l', None, -2) + self.checkequal(0, s, 'rfind', 'h', None, None) + + self.checkequal(2, s, 'index', 'l', None) + self.checkequal(3, s, 'index', 'l', -2, None) + self.checkequal(2, s, 'index', 'l', None, -2) + self.checkequal(0, s, 'index', 'h', None, None) + + self.checkequal(3, s, 'rindex', 'l', None) + self.checkequal(3, s, 'rindex', 'l', -2, None) + self.checkequal(2, s, 'rindex', 'l', None, -2) + self.checkequal(0, s, 'rindex', 'h', None, None) + + self.checkequal(2, s, 'count', 'l', None) + self.checkequal(1, s, 'count', 'l', -2, None) + self.checkequal(1, s, 'count', 'l', None, -2) + self.checkequal(0, s, 'count', 'x', None, None) + + self.checkequal(True, s, 'endswith', 'o', None) + self.checkequal(True, s, 'endswith', 'lo', -2, None) + self.checkequal(True, s, 'endswith', 'l', None, -2) + self.checkequal(False, s, 'endswith', 'x', None, None) + + self.checkequal(True, s, 'startswith', 'h', None) + self.checkequal(True, s, 'startswith', 'l', -2, None) + self.checkequal(True, s, 'startswith', 'h', None, -2) + self.checkequal(False, s, 'startswith', 'x', None, None) + + def test_find_etc_raise_correct_error_messages(self): + # issue 11828 + s = 'hello' + x = 'x' + self.assertRaisesRegexp(TypeError, r'^find\(', s.find, + x, None, None, None) + self.assertRaisesRegexp(TypeError, r'^rfind\(', s.rfind, + x, None, None, None) + self.assertRaisesRegexp(TypeError, r'^index\(', s.index, + x, None, None, None) + self.assertRaisesRegexp(TypeError, r'^rindex\(', s.rindex, + x, None, None, None) + self.assertRaisesRegexp(TypeError, r'^count\(', s.count, + x, None, None, None) + self.assertRaisesRegexp(TypeError, r'^startswith\(', s.startswith, + x, None, None, None) + self.assertRaisesRegexp(TypeError, r'^endswith\(', s.endswith, + x, None, None, None) + class MixinStrUnicodeTest: # Additional tests that only work with str and unicode. 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 @@ -478,6 +478,68 @@ self.assertRaises(ValueError, self.type2test.maketrans, b'abc', b'xyzq') self.assertRaises(TypeError, self.type2test.maketrans, 'abc', 'def') + def test_none_arguments(self): + # issue 11828 + b = self.type2test(b'hello') + l = self.type2test(b'l') + h = self.type2test(b'h') + x = self.type2test(b'x') + o = self.type2test(b'o') + + self.assertEqual(2, b.find(l, None)) + self.assertEqual(3, b.find(l, -2, None)) + self.assertEqual(2, b.find(l, None, -2)) + self.assertEqual(0, b.find(h, None, None)) + + self.assertEqual(3, b.rfind(l, None)) + self.assertEqual(3, b.rfind(l, -2, None)) + self.assertEqual(2, b.rfind(l, None, -2)) + self.assertEqual(0, b.rfind(h, None, None)) + + self.assertEqual(2, b.index(l, None)) + self.assertEqual(3, b.index(l, -2, None)) + self.assertEqual(2, b.index(l, None, -2)) + self.assertEqual(0, b.index(h, None, None)) + + self.assertEqual(3, b.rindex(l, None)) + self.assertEqual(3, b.rindex(l, -2, None)) + self.assertEqual(2, b.rindex(l, None, -2)) + self.assertEqual(0, b.rindex(h, None, None)) + + self.assertEqual(2, b.count(l, None)) + self.assertEqual(1, b.count(l, -2, None)) + self.assertEqual(1, b.count(l, None, -2)) + self.assertEqual(0, b.count(x, None, None)) + + self.assertEqual(True, b.endswith(o, None)) + self.assertEqual(True, b.endswith(o, -2, None)) + self.assertEqual(True, b.endswith(l, None, -2)) + self.assertEqual(False, b.endswith(x, None, None)) + + self.assertEqual(True, b.startswith(h, None)) + self.assertEqual(True, b.startswith(l, -2, None)) + self.assertEqual(True, b.startswith(h, None, -2)) + self.assertEqual(False, b.startswith(x, None, None)) + + def test_find_etc_raise_correct_error_messages(self): + # issue 11828 + b = self.type2test(b'hello') + x = self.type2test(b'x') + self.assertRaisesRegexp(TypeError, r'\bfind\b', b.find, + x, None, None, None) + self.assertRaisesRegexp(TypeError, r'\brfind\b', b.rfind, + x, None, None, None) + self.assertRaisesRegexp(TypeError, r'\bindex\b', b.index, + x, None, None, None) + self.assertRaisesRegexp(TypeError, r'\brindex\b', b.rindex, + x, None, None, None) + self.assertRaisesRegexp(TypeError, r'\bcount\b', b.count, + x, None, None, None) + self.assertRaisesRegexp(TypeError, r'\bstartswith\b', b.startswith, + x, None, None, None) + self.assertRaisesRegexp(TypeError, r'\bendswith\b', b.endswith, + x, None, None, None) + class BytesTest(BaseBytesTest): type2test = bytes diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -67,6 +67,7 @@ David Beazley Robin Becker Neal Becker +Torsten Becker Bill Bedford Stefan Behnel Reimer Behrends diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -88,6 +88,9 @@ - Issue #11272: On Windows, input() strips '\r' (and not only '\n'), and sys.stdin uses universal newline (replace '\r\n' by '\n'). +- issue #11828: startswith and endswith don't accept None as slice index. + Patch by Torsten Becker. + - Issue #10830: Fix PyUnicode_FromFormatV("%c") for non-BMP characters on narrow build. diff --git a/Objects/bytearrayobject.c b/Objects/bytearrayobject.c --- a/Objects/bytearrayobject.c +++ b/Objects/bytearrayobject.c @@ -1081,8 +1081,8 @@ Py_ssize_t start=0, end=PY_SSIZE_T_MAX; Py_ssize_t res; - if (!PyArg_ParseTuple(args, "O|O&O&:find/rfind/index/rindex", &subobj, - _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) + if (!stringlib_parse_args_finds("find/rfind/index/rindex", + args, &subobj, &start, &end)) return -2; if (_getbuffer(subobj, &subbuf) < 0) return -2; @@ -1132,8 +1132,7 @@ Py_buffer vsub; PyObject *count_obj; - if (!PyArg_ParseTuple(args, "O|O&O&:count", &sub_obj, - _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) + if (!stringlib_parse_args_finds("count", args, &sub_obj, &start, &end)) return NULL; if (_getbuffer(sub_obj, &vsub) < 0) @@ -1315,8 +1314,7 @@ PyObject *subobj; int result; - if (!PyArg_ParseTuple(args, "O|O&O&:startswith", &subobj, - _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) + if (!stringlib_parse_args_finds("startswith", args, &subobj, &start, &end)) return NULL; if (PyTuple_Check(subobj)) { Py_ssize_t i; @@ -1355,8 +1353,7 @@ PyObject *subobj; int result; - if (!PyArg_ParseTuple(args, "O|O&O&:endswith", &subobj, - _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) + if (!stringlib_parse_args_finds("endswith", args, &subobj, &start, &end)) return NULL; if (PyTuple_Check(subobj)) { Py_ssize_t i; diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -1240,19 +1240,9 @@ const char *sub; Py_ssize_t sub_len; Py_ssize_t start=0, end=PY_SSIZE_T_MAX; - PyObject *obj_start=Py_None, *obj_end=Py_None; - - if (!PyArg_ParseTuple(args, "O|OO:find/rfind/index/rindex", &subobj, - &obj_start, &obj_end)) - return -2; - /* To support None in "start" and "end" arguments, meaning - the same as if they were not passed. - */ - if (obj_start != Py_None) - if (!_PyEval_SliceIndex(obj_start, &start)) - return -2; - if (obj_end != Py_None) - if (!_PyEval_SliceIndex(obj_end, &end)) + + if (!stringlib_parse_args_finds("find/rfind/index/rindex", + args, &subobj, &start, &end)) return -2; if (PyBytes_Check(subobj)) { @@ -1499,8 +1489,7 @@ Py_ssize_t sub_len; Py_ssize_t start = 0, end = PY_SSIZE_T_MAX; - if (!PyArg_ParseTuple(args, "O|O&O&:count", &sub_obj, - _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) + if (!stringlib_parse_args_finds("count", args, &sub_obj, &start, &end)) return NULL; if (PyBytes_Check(sub_obj)) { @@ -2218,8 +2207,7 @@ PyObject *subobj; int result; - if (!PyArg_ParseTuple(args, "O|O&O&:startswith", &subobj, - _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) + if (!stringlib_parse_args_finds("startswith", args, &subobj, &start, &end)) return NULL; if (PyTuple_Check(subobj)) { Py_ssize_t i; @@ -2259,8 +2247,7 @@ PyObject *subobj; int result; - if (!PyArg_ParseTuple(args, "O|O&O&:endswith", &subobj, - _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) + if (!stringlib_parse_args_finds("endswith", args, &subobj, &start, &end)) return NULL; if (PyTuple_Check(subobj)) { Py_ssize_t i; diff --git a/Objects/stringlib/find.h b/Objects/stringlib/find.h --- a/Objects/stringlib/find.h +++ b/Objects/stringlib/find.h @@ -93,32 +93,33 @@ #endif /* STRINGLIB_WANT_CONTAINS_OBJ */ -#if STRINGLIB_IS_UNICODE - /* This function is a helper for the "find" family (find, rfind, index, -rindex) of unicodeobject.c file, because they all have the same -behaviour for the arguments. +rindex) and for count, startswith and endswith, because they all have +the same behaviour for the arguments. It does not touch the variables received until it knows everything is ok. - -Note that we receive a pointer to the pointer of the substring object, -so when we create that object in this function we don't DECREF it, -because it continues living in the caller functions (those functions, -after finishing using the substring, must DECREF it). */ +#define FORMAT_BUFFER_SIZE 50 + Py_LOCAL_INLINE(int) -_ParseTupleFinds (PyObject *args, PyObject **substring, - Py_ssize_t *start, Py_ssize_t *end) { - PyObject *tmp_substring; +stringlib_parse_args_finds(const char * function_name, PyObject *args, + PyObject **subobj, + Py_ssize_t *start, Py_ssize_t *end) +{ + PyObject *tmp_subobj; Py_ssize_t tmp_start = 0; Py_ssize_t tmp_end = PY_SSIZE_T_MAX; PyObject *obj_start=Py_None, *obj_end=Py_None; + char format[FORMAT_BUFFER_SIZE] = "O|OO:"; + size_t len = strlen(format); - if (!PyArg_ParseTuple(args, "O|OO:find", &tmp_substring, - &obj_start, &obj_end)) + strncpy(format + len, function_name, FORMAT_BUFFER_SIZE - len - 1); + format[FORMAT_BUFFER_SIZE - 1] = '\0'; + + if (!PyArg_ParseTuple(args, format, &tmp_subobj, &obj_start, &obj_end)) return 0; /* To support None in "start" and "end" arguments, meaning @@ -131,16 +132,44 @@ if (!_PyEval_SliceIndex(obj_end, &tmp_end)) return 0; - tmp_substring = PyUnicode_FromObject(tmp_substring); - if (!tmp_substring) - return 0; - *start = tmp_start; *end = tmp_end; - *substring = tmp_substring; + *subobj = tmp_subobj; return 1; } +#undef FORMAT_BUFFER_SIZE + +#if STRINGLIB_IS_UNICODE + +/* +Wraps stringlib_parse_args_finds() and additionally ensures that the +first argument is a unicode object. + +Note that we receive a pointer to the pointer of the substring object, +so when we create that object in this function we don't DECREF it, +because it continues living in the caller functions (those functions, +after finishing using the substring, must DECREF it). +*/ + +Py_LOCAL_INLINE(int) +stringlib_parse_args_finds_unicode(const char * function_name, PyObject *args, + PyUnicodeObject **substring, + Py_ssize_t *start, Py_ssize_t *end) +{ + PyObject *tmp_substring; + + if(stringlib_parse_args_finds(function_name, args, &tmp_substring, + start, end)) { + tmp_substring = PyUnicode_FromObject(tmp_substring); + if (!tmp_substring) + return 0; + *substring = (PyUnicodeObject *)tmp_substring; + return 1; + } + return 0; +} + #endif /* STRINGLIB_IS_UNICODE */ #endif /* STRINGLIB_FIND_H */ diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -7515,13 +7515,8 @@ Py_ssize_t end = PY_SSIZE_T_MAX; PyObject *result; - if (!PyArg_ParseTuple(args, "O|O&O&:count", &substring, - _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) - return NULL; - - substring = (PyUnicodeObject *)PyUnicode_FromObject( - (PyObject *)substring); - if (substring == NULL) + if (!stringlib_parse_args_finds_unicode("count", args, &substring, + &start, &end)) return NULL; ADJUST_INDICES(start, end, self->length); @@ -7658,12 +7653,13 @@ static PyObject * unicode_find(PyUnicodeObject *self, PyObject *args) { - PyObject *substring; + PyUnicodeObject *substring; Py_ssize_t start; Py_ssize_t end; Py_ssize_t result; - if (!_ParseTupleFinds(args, &substring, &start, &end)) + if (!stringlib_parse_args_finds_unicode("find", args, &substring, + &start, &end)) return NULL; result = stringlib_find_slice( @@ -7720,11 +7716,12 @@ unicode_index(PyUnicodeObject *self, PyObject *args) { Py_ssize_t result; - PyObject *substring; + PyUnicodeObject *substring; Py_ssize_t start; Py_ssize_t end; - if (!_ParseTupleFinds(args, &substring, &start, &end)) + if (!stringlib_parse_args_finds_unicode("index", args, &substring, + &start, &end)) return NULL; result = stringlib_find_slice( @@ -8583,12 +8580,13 @@ static PyObject * unicode_rfind(PyUnicodeObject *self, PyObject *args) { - PyObject *substring; + PyUnicodeObject *substring; Py_ssize_t start; Py_ssize_t end; Py_ssize_t result; - if (!_ParseTupleFinds(args, &substring, &start, &end)) + if (!stringlib_parse_args_finds_unicode("rfind", args, &substring, + &start, &end)) return NULL; result = stringlib_rfind_slice( @@ -8610,12 +8608,13 @@ static PyObject * unicode_rindex(PyUnicodeObject *self, PyObject *args) { - PyObject *substring; + PyUnicodeObject *substring; Py_ssize_t start; Py_ssize_t end; Py_ssize_t result; - if (!_ParseTupleFinds(args, &substring, &start, &end)) + if (!stringlib_parse_args_finds_unicode("rindex", args, &substring, + &start, &end)) return NULL; result = stringlib_rfind_slice( @@ -9083,8 +9082,7 @@ Py_ssize_t end = PY_SSIZE_T_MAX; int result; - if (!PyArg_ParseTuple(args, "O|O&O&:startswith", &subobj, - _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) + if (!stringlib_parse_args_finds("startswith", args, &subobj, &start, &end)) return NULL; if (PyTuple_Check(subobj)) { Py_ssize_t i; @@ -9129,8 +9127,7 @@ Py_ssize_t end = PY_SSIZE_T_MAX; int result; - if (!PyArg_ParseTuple(args, "O|O&O&:endswith", &subobj, - _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) + if (!stringlib_parse_args_finds("endswith", args, &subobj, &start, &end)) return NULL; if (PyTuple_Check(subobj)) { Py_ssize_t i; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 20 20:33:58 2011 From: python-checkins at python.org (ezio.melotti) Date: Wed, 20 Apr 2011 20:33:58 +0200 Subject: [Python-checkins] cpython (2.7): Fix wrong function name. Noticed by Clive Darke. Message-ID: http://hg.python.org/cpython/rev/1eaf6b9897eb changeset: 69475:1eaf6b9897eb branch: 2.7 parent: 69471:f4da64529e8c user: Ezio Melotti date: Wed Apr 20 21:29:31 2011 +0300 summary: Fix wrong function name. Noticed by Clive Darke. files: Doc/c-api/init.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -474,7 +474,7 @@ :ref:`lock-objects` in the child. When extending or embedding Python, there is no way to inform Python of additional (non-Python) locks that need to be acquired before or reset after a fork. OS facilities such as -:cfunc:`posix_atfork` would need to be used to accomplish the same thing. +:cfunc:`pthread_atfork` would need to be used to accomplish the same thing. Additionally, when extending or embedding Python, calling :cfunc:`fork` directly rather than through :func:`os.fork` (and returning to or calling into Python) may result in a deadlock by one of Python's internal locks -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 20 20:34:01 2011 From: python-checkins at python.org (ezio.melotti) Date: Wed, 20 Apr 2011 20:34:01 +0200 Subject: [Python-checkins] cpython (3.1): Fix wrong function name. Noticed by Clive Darke. Message-ID: http://hg.python.org/cpython/rev/96072a9950ef changeset: 69476:96072a9950ef branch: 3.1 parent: 69472:77c657e47b5c user: Ezio Melotti date: Wed Apr 20 21:29:31 2011 +0300 summary: Fix wrong function name. Noticed by Clive Darke. files: Doc/c-api/init.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -472,7 +472,7 @@ :ref:`lock-objects` in the child. When extending or embedding Python, there is no way to inform Python of additional (non-Python) locks that need to be acquired before or reset after a fork. OS facilities such as -:cfunc:`posix_atfork` would need to be used to accomplish the same thing. +:cfunc:`pthread_atfork` would need to be used to accomplish the same thing. Additionally, when extending or embedding Python, calling :cfunc:`fork` directly rather than through :func:`os.fork` (and returning to or calling into Python) may result in a deadlock by one of Python's internal locks -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 20 20:34:05 2011 From: python-checkins at python.org (ezio.melotti) Date: Wed, 20 Apr 2011 20:34:05 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): Merge with 3.1. Message-ID: http://hg.python.org/cpython/rev/a2a2882ce6b4 changeset: 69477:a2a2882ce6b4 branch: 3.2 parent: 69473:e5f11efe89a6 parent: 69476:96072a9950ef user: Ezio Melotti date: Wed Apr 20 21:32:40 2011 +0300 summary: Merge with 3.1. files: Doc/c-api/init.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -489,7 +489,7 @@ :ref:`lock-objects` in the child. When extending or embedding Python, there is no way to inform Python of additional (non-Python) locks that need to be acquired before or reset after a fork. OS facilities such as -:c:func:`posix_atfork` would need to be used to accomplish the same thing. +:c:func:`pthread_atfork` would need to be used to accomplish the same thing. Additionally, when extending or embedding Python, calling :c:func:`fork` directly rather than through :func:`os.fork` (and returning to or calling into Python) may result in a deadlock by one of Python's internal locks -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 20 20:34:08 2011 From: python-checkins at python.org (ezio.melotti) Date: Wed, 20 Apr 2011 20:34:08 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge with 3.2. Message-ID: http://hg.python.org/cpython/rev/d065afeaff50 changeset: 69478:d065afeaff50 parent: 69474:b8d1cf9fde04 parent: 69477:a2a2882ce6b4 user: Ezio Melotti date: Wed Apr 20 21:33:29 2011 +0300 summary: Merge with 3.2. files: Doc/c-api/init.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -489,7 +489,7 @@ :ref:`lock-objects` in the child. When extending or embedding Python, there is no way to inform Python of additional (non-Python) locks that need to be acquired before or reset after a fork. OS facilities such as -:c:func:`posix_atfork` would need to be used to accomplish the same thing. +:c:func:`pthread_atfork` would need to be used to accomplish the same thing. Additionally, when extending or embedding Python, calling :c:func:`fork` directly rather than through :func:`os.fork` (and returning to or calling into Python) may result in a deadlock by one of Python's internal locks -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 20 20:59:32 2011 From: python-checkins at python.org (ezio.melotti) Date: Wed, 20 Apr 2011 20:59:32 +0200 Subject: [Python-checkins] cpython (3.2): Use non-deprecated method name. Message-ID: http://hg.python.org/cpython/rev/87f9519203f4 changeset: 69479:87f9519203f4 branch: 3.2 parent: 69477:a2a2882ce6b4 user: Ezio Melotti date: Wed Apr 20 21:56:21 2011 +0300 summary: Use non-deprecated method name. files: Lib/test/string_tests.py | 14 +++++++------- Lib/test/test_bytes.py | 14 +++++++------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Lib/test/string_tests.py b/Lib/test/string_tests.py --- a/Lib/test/string_tests.py +++ b/Lib/test/string_tests.py @@ -1225,19 +1225,19 @@ # issue 11828 s = 'hello' x = 'x' - self.assertRaisesRegexp(TypeError, r'^find\(', s.find, + self.assertRaisesRegex(TypeError, r'^find\(', s.find, x, None, None, None) - self.assertRaisesRegexp(TypeError, r'^rfind\(', s.rfind, + self.assertRaisesRegex(TypeError, r'^rfind\(', s.rfind, x, None, None, None) - self.assertRaisesRegexp(TypeError, r'^index\(', s.index, + self.assertRaisesRegex(TypeError, r'^index\(', s.index, x, None, None, None) - self.assertRaisesRegexp(TypeError, r'^rindex\(', s.rindex, + self.assertRaisesRegex(TypeError, r'^rindex\(', s.rindex, x, None, None, None) - self.assertRaisesRegexp(TypeError, r'^count\(', s.count, + self.assertRaisesRegex(TypeError, r'^count\(', s.count, x, None, None, None) - self.assertRaisesRegexp(TypeError, r'^startswith\(', s.startswith, + self.assertRaisesRegex(TypeError, r'^startswith\(', s.startswith, x, None, None, None) - self.assertRaisesRegexp(TypeError, r'^endswith\(', s.endswith, + self.assertRaisesRegex(TypeError, r'^endswith\(', s.endswith, x, None, None, None) 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 @@ -523,19 +523,19 @@ # issue 11828 b = self.type2test(b'hello') x = self.type2test(b'x') - self.assertRaisesRegexp(TypeError, r'\bfind\b', b.find, + self.assertRaisesRegex(TypeError, r'\bfind\b', b.find, x, None, None, None) - self.assertRaisesRegexp(TypeError, r'\brfind\b', b.rfind, + self.assertRaisesRegex(TypeError, r'\brfind\b', b.rfind, x, None, None, None) - self.assertRaisesRegexp(TypeError, r'\bindex\b', b.index, + self.assertRaisesRegex(TypeError, r'\bindex\b', b.index, x, None, None, None) - self.assertRaisesRegexp(TypeError, r'\brindex\b', b.rindex, + self.assertRaisesRegex(TypeError, r'\brindex\b', b.rindex, x, None, None, None) - self.assertRaisesRegexp(TypeError, r'\bcount\b', b.count, + self.assertRaisesRegex(TypeError, r'\bcount\b', b.count, x, None, None, None) - self.assertRaisesRegexp(TypeError, r'\bstartswith\b', b.startswith, + self.assertRaisesRegex(TypeError, r'\bstartswith\b', b.startswith, x, None, None, None) - self.assertRaisesRegexp(TypeError, r'\bendswith\b', b.endswith, + self.assertRaisesRegex(TypeError, r'\bendswith\b', b.endswith, x, None, None, None) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 20 20:59:35 2011 From: python-checkins at python.org (ezio.melotti) Date: Wed, 20 Apr 2011 20:59:35 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge with 3.2. Message-ID: http://hg.python.org/cpython/rev/71d4925a1364 changeset: 69480:71d4925a1364 parent: 69478:d065afeaff50 parent: 69479:87f9519203f4 user: Ezio Melotti date: Wed Apr 20 21:59:06 2011 +0300 summary: Merge with 3.2. files: Lib/test/string_tests.py | 14 +++++++------- Lib/test/test_bytes.py | 14 +++++++------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Lib/test/string_tests.py b/Lib/test/string_tests.py --- a/Lib/test/string_tests.py +++ b/Lib/test/string_tests.py @@ -1225,19 +1225,19 @@ # issue 11828 s = 'hello' x = 'x' - self.assertRaisesRegexp(TypeError, r'^find\(', s.find, + self.assertRaisesRegex(TypeError, r'^find\(', s.find, x, None, None, None) - self.assertRaisesRegexp(TypeError, r'^rfind\(', s.rfind, + self.assertRaisesRegex(TypeError, r'^rfind\(', s.rfind, x, None, None, None) - self.assertRaisesRegexp(TypeError, r'^index\(', s.index, + self.assertRaisesRegex(TypeError, r'^index\(', s.index, x, None, None, None) - self.assertRaisesRegexp(TypeError, r'^rindex\(', s.rindex, + self.assertRaisesRegex(TypeError, r'^rindex\(', s.rindex, x, None, None, None) - self.assertRaisesRegexp(TypeError, r'^count\(', s.count, + self.assertRaisesRegex(TypeError, r'^count\(', s.count, x, None, None, None) - self.assertRaisesRegexp(TypeError, r'^startswith\(', s.startswith, + self.assertRaisesRegex(TypeError, r'^startswith\(', s.startswith, x, None, None, None) - self.assertRaisesRegexp(TypeError, r'^endswith\(', s.endswith, + self.assertRaisesRegex(TypeError, r'^endswith\(', s.endswith, x, None, None, None) 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 @@ -525,19 +525,19 @@ # issue 11828 b = self.type2test(b'hello') x = self.type2test(b'x') - self.assertRaisesRegexp(TypeError, r'\bfind\b', b.find, + self.assertRaisesRegex(TypeError, r'\bfind\b', b.find, x, None, None, None) - self.assertRaisesRegexp(TypeError, r'\brfind\b', b.rfind, + self.assertRaisesRegex(TypeError, r'\brfind\b', b.rfind, x, None, None, None) - self.assertRaisesRegexp(TypeError, r'\bindex\b', b.index, + self.assertRaisesRegex(TypeError, r'\bindex\b', b.index, x, None, None, None) - self.assertRaisesRegexp(TypeError, r'\brindex\b', b.rindex, + self.assertRaisesRegex(TypeError, r'\brindex\b', b.rindex, x, None, None, None) - self.assertRaisesRegexp(TypeError, r'\bcount\b', b.count, + self.assertRaisesRegex(TypeError, r'\bcount\b', b.count, x, None, None, None) - self.assertRaisesRegexp(TypeError, r'\bstartswith\b', b.startswith, + self.assertRaisesRegex(TypeError, r'\bstartswith\b', b.startswith, x, None, None, None) - self.assertRaisesRegexp(TypeError, r'\bendswith\b', b.endswith, + self.assertRaisesRegex(TypeError, r'\bendswith\b', b.endswith, x, None, None, None) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 20 21:14:37 2011 From: python-checkins at python.org (jesus.cea) Date: Wed, 20 Apr 2011 21:14:37 +0200 Subject: [Python-checkins] cpython (3.1): Up-port changeset 5cf8f6da8743 (closes #11890) Message-ID: http://hg.python.org/cpython/rev/febb6cf195e7 changeset: 69481:febb6cf195e7 branch: 3.1 parent: 69472:77c657e47b5c user: Jesus Cea date: Wed Apr 20 20:24:57 2011 +0200 summary: Up-port changeset 5cf8f6da8743 (closes #11890) files: Python/sysmodule.c | 60 ++------------------------------- 1 files changed, 4 insertions(+), 56 deletions(-) diff --git a/Python/sysmodule.c b/Python/sysmodule.c --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -1065,8 +1065,6 @@ /* end of sys_doc */ ; /* Subversion branch and revision management */ -static const char _patchlevel_revision[] = PY_PATCHLEVEL_REVISION; -static const char headurl[] = "$HeadURL$"; static int svn_initialized; static char patchlevel_revision[50]; /* Just the number */ static char branch[50]; @@ -1076,64 +1074,14 @@ static void svnversion_init(void) { - const char *python, *br_start, *br_end, *br_end2, *svnversion; - Py_ssize_t len; - int istag = 0; - if (svn_initialized) return; - python = strstr(headurl, "/python/"); - if (!python) { - strcpy(branch, "unknown branch"); - strcpy(shortbranch, "unknown"); - } - else { - br_start = python + 8; - br_end = strchr(br_start, '/'); - assert(br_end); - - /* Works even for trunk, - as we are in trunk/Python/sysmodule.c */ - br_end2 = strchr(br_end+1, '/'); - - istag = strncmp(br_start, "tags", 4) == 0; - if (strncmp(br_start, "trunk", 5) == 0) { - strcpy(branch, "trunk"); - strcpy(shortbranch, "trunk"); - } - else if (istag || strncmp(br_start, "branches", 8) == 0) { - len = br_end2 - br_start; - strncpy(branch, br_start, len); - branch[len] = '\0'; - - len = br_end2 - (br_end + 1); - strncpy(shortbranch, br_end + 1, len); - shortbranch[len] = '\0'; - } - else { - Py_FatalError("bad HeadURL"); - return; - } - } - - - svnversion = _Py_svnversion(); - if (strcmp(svnversion, "Unversioned directory") != 0 && strcmp(svnversion, "exported") != 0) - svn_revision = svnversion; - else if (istag) { - len = strlen(_patchlevel_revision); - assert(len >= 13); - assert(len < (sizeof(patchlevel_revision) + 13)); - strncpy(patchlevel_revision, _patchlevel_revision + 11, - len - 13); - patchlevel_revision[len - 13] = '\0'; - svn_revision = patchlevel_revision; - } - else - svn_revision = ""; - svn_initialized = 1; + *patchlevel_revision = '\0'; + strcpy(branch, ""); + strcpy(shortbranch, "unknown"); + svn_revision = ""; } /* Return svnversion output if available. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 20 21:14:40 2011 From: python-checkins at python.org (jesus.cea) Date: Wed, 20 Apr 2011 21:14:40 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): MERGE: Up-port changeset 5cf8f6da8743 (closes #11890) Message-ID: http://hg.python.org/cpython/rev/063b4ab49fcc changeset: 69482:063b4ab49fcc branch: 3.2 parent: 69473:e5f11efe89a6 parent: 69481:febb6cf195e7 user: Jesus Cea date: Wed Apr 20 20:32:52 2011 +0200 summary: MERGE: Up-port changeset 5cf8f6da8743 (closes #11890) files: Python/sysmodule.c | 60 ++------------------------------- 1 files changed, 4 insertions(+), 56 deletions(-) diff --git a/Python/sysmodule.c b/Python/sysmodule.c --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -1306,8 +1306,6 @@ /* end of sys_doc */ ; /* Subversion branch and revision management */ -static const char _patchlevel_revision[] = PY_PATCHLEVEL_REVISION; -static const char headurl[] = "$HeadURL$"; static int svn_initialized; static char patchlevel_revision[50]; /* Just the number */ static char branch[50]; @@ -1317,64 +1315,14 @@ static void svnversion_init(void) { - const char *python, *br_start, *br_end, *br_end2, *svnversion; - Py_ssize_t len; - int istag = 0; - if (svn_initialized) return; - python = strstr(headurl, "/python/"); - if (!python) { - strcpy(branch, "unknown branch"); - strcpy(shortbranch, "unknown"); - } - else { - br_start = python + 8; - br_end = strchr(br_start, '/'); - assert(br_end); - - /* Works even for trunk, - as we are in trunk/Python/sysmodule.c */ - br_end2 = strchr(br_end+1, '/'); - - istag = strncmp(br_start, "tags", 4) == 0; - if (strncmp(br_start, "trunk", 5) == 0) { - strcpy(branch, "trunk"); - strcpy(shortbranch, "trunk"); - } - else if (istag || strncmp(br_start, "branches", 8) == 0) { - len = br_end2 - br_start; - strncpy(branch, br_start, len); - branch[len] = '\0'; - - len = br_end2 - (br_end + 1); - strncpy(shortbranch, br_end + 1, len); - shortbranch[len] = '\0'; - } - else { - Py_FatalError("bad HeadURL"); - return; - } - } - - - svnversion = _Py_svnversion(); - if (strcmp(svnversion, "Unversioned directory") != 0 && strcmp(svnversion, "exported") != 0) - svn_revision = svnversion; - else if (istag) { - len = strlen(_patchlevel_revision); - assert(len >= 13); - assert(len < (sizeof(patchlevel_revision) + 13)); - strncpy(patchlevel_revision, _patchlevel_revision + 11, - len - 13); - patchlevel_revision[len - 13] = '\0'; - svn_revision = patchlevel_revision; - } - else - svn_revision = ""; - svn_initialized = 1; + *patchlevel_revision = '\0'; + strcpy(branch, ""); + strcpy(shortbranch, "unknown"); + svn_revision = ""; } /* Return svnversion output if available. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 20 21:14:41 2011 From: python-checkins at python.org (jesus.cea) Date: Wed, 20 Apr 2011 21:14:41 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): null merge Message-ID: http://hg.python.org/cpython/rev/c65035463b0f changeset: 69483:c65035463b0f parent: 69478:d065afeaff50 parent: 69482:063b4ab49fcc user: Jesus Cea date: Wed Apr 20 20:49:06 2011 +0200 summary: null merge files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 20 21:14:45 2011 From: python-checkins at python.org (jesus.cea) Date: Wed, 20 Apr 2011 21:14:45 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.1): merge Message-ID: http://hg.python.org/cpython/rev/ef95702b555e changeset: 69484:ef95702b555e branch: 3.1 parent: 69476:96072a9950ef parent: 69481:febb6cf195e7 user: Jesus Cea date: Wed Apr 20 20:51:09 2011 +0200 summary: merge files: Python/sysmodule.c | 60 ++------------------------------- 1 files changed, 4 insertions(+), 56 deletions(-) diff --git a/Python/sysmodule.c b/Python/sysmodule.c --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -1065,8 +1065,6 @@ /* end of sys_doc */ ; /* Subversion branch and revision management */ -static const char _patchlevel_revision[] = PY_PATCHLEVEL_REVISION; -static const char headurl[] = "$HeadURL$"; static int svn_initialized; static char patchlevel_revision[50]; /* Just the number */ static char branch[50]; @@ -1076,64 +1074,14 @@ static void svnversion_init(void) { - const char *python, *br_start, *br_end, *br_end2, *svnversion; - Py_ssize_t len; - int istag = 0; - if (svn_initialized) return; - python = strstr(headurl, "/python/"); - if (!python) { - strcpy(branch, "unknown branch"); - strcpy(shortbranch, "unknown"); - } - else { - br_start = python + 8; - br_end = strchr(br_start, '/'); - assert(br_end); - - /* Works even for trunk, - as we are in trunk/Python/sysmodule.c */ - br_end2 = strchr(br_end+1, '/'); - - istag = strncmp(br_start, "tags", 4) == 0; - if (strncmp(br_start, "trunk", 5) == 0) { - strcpy(branch, "trunk"); - strcpy(shortbranch, "trunk"); - } - else if (istag || strncmp(br_start, "branches", 8) == 0) { - len = br_end2 - br_start; - strncpy(branch, br_start, len); - branch[len] = '\0'; - - len = br_end2 - (br_end + 1); - strncpy(shortbranch, br_end + 1, len); - shortbranch[len] = '\0'; - } - else { - Py_FatalError("bad HeadURL"); - return; - } - } - - - svnversion = _Py_svnversion(); - if (strcmp(svnversion, "Unversioned directory") != 0 && strcmp(svnversion, "exported") != 0) - svn_revision = svnversion; - else if (istag) { - len = strlen(_patchlevel_revision); - assert(len >= 13); - assert(len < (sizeof(patchlevel_revision) + 13)); - strncpy(patchlevel_revision, _patchlevel_revision + 11, - len - 13); - patchlevel_revision[len - 13] = '\0'; - svn_revision = patchlevel_revision; - } - else - svn_revision = ""; - svn_initialized = 1; + *patchlevel_revision = '\0'; + strcpy(branch, ""); + strcpy(shortbranch, "unknown"); + svn_revision = ""; } /* Return svnversion output if available. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 20 21:14:49 2011 From: python-checkins at python.org (jesus.cea) Date: Wed, 20 Apr 2011 21:14:49 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> 3.2): merge Message-ID: http://hg.python.org/cpython/rev/e3195317c62a changeset: 69485:e3195317c62a branch: 3.2 parent: 69477:a2a2882ce6b4 parent: 69482:063b4ab49fcc user: Jesus Cea date: Wed Apr 20 20:51:59 2011 +0200 summary: merge files: Python/sysmodule.c | 60 ++------------------------------- 1 files changed, 4 insertions(+), 56 deletions(-) diff --git a/Python/sysmodule.c b/Python/sysmodule.c --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -1306,8 +1306,6 @@ /* end of sys_doc */ ; /* Subversion branch and revision management */ -static const char _patchlevel_revision[] = PY_PATCHLEVEL_REVISION; -static const char headurl[] = "$HeadURL$"; static int svn_initialized; static char patchlevel_revision[50]; /* Just the number */ static char branch[50]; @@ -1317,64 +1315,14 @@ static void svnversion_init(void) { - const char *python, *br_start, *br_end, *br_end2, *svnversion; - Py_ssize_t len; - int istag = 0; - if (svn_initialized) return; - python = strstr(headurl, "/python/"); - if (!python) { - strcpy(branch, "unknown branch"); - strcpy(shortbranch, "unknown"); - } - else { - br_start = python + 8; - br_end = strchr(br_start, '/'); - assert(br_end); - - /* Works even for trunk, - as we are in trunk/Python/sysmodule.c */ - br_end2 = strchr(br_end+1, '/'); - - istag = strncmp(br_start, "tags", 4) == 0; - if (strncmp(br_start, "trunk", 5) == 0) { - strcpy(branch, "trunk"); - strcpy(shortbranch, "trunk"); - } - else if (istag || strncmp(br_start, "branches", 8) == 0) { - len = br_end2 - br_start; - strncpy(branch, br_start, len); - branch[len] = '\0'; - - len = br_end2 - (br_end + 1); - strncpy(shortbranch, br_end + 1, len); - shortbranch[len] = '\0'; - } - else { - Py_FatalError("bad HeadURL"); - return; - } - } - - - svnversion = _Py_svnversion(); - if (strcmp(svnversion, "Unversioned directory") != 0 && strcmp(svnversion, "exported") != 0) - svn_revision = svnversion; - else if (istag) { - len = strlen(_patchlevel_revision); - assert(len >= 13); - assert(len < (sizeof(patchlevel_revision) + 13)); - strncpy(patchlevel_revision, _patchlevel_revision + 11, - len - 13); - patchlevel_revision[len - 13] = '\0'; - svn_revision = patchlevel_revision; - } - else - svn_revision = ""; - svn_initialized = 1; + *patchlevel_revision = '\0'; + strcpy(branch, ""); + strcpy(shortbranch, "unknown"); + svn_revision = ""; } /* Return svnversion output if available. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 20 21:14:50 2011 From: python-checkins at python.org (jesus.cea) Date: Wed, 20 Apr 2011 21:14:50 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): null merge Message-ID: http://hg.python.org/cpython/rev/8f0c830051ee changeset: 69486:8f0c830051ee parent: 69483:c65035463b0f parent: 69485:e3195317c62a user: Jesus Cea date: Wed Apr 20 20:54:05 2011 +0200 summary: null merge files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 20 21:14:51 2011 From: python-checkins at python.org (jesus.cea) Date: Wed, 20 Apr 2011 21:14:51 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): null merge Message-ID: http://hg.python.org/cpython/rev/28e661ab5453 changeset: 69487:28e661ab5453 branch: 3.2 parent: 69485:e3195317c62a parent: 69484:ef95702b555e user: Jesus Cea date: Wed Apr 20 21:00:40 2011 +0200 summary: null merge files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 20 21:14:53 2011 From: python-checkins at python.org (jesus.cea) Date: Wed, 20 Apr 2011 21:14:53 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): null merge Message-ID: http://hg.python.org/cpython/rev/784127390130 changeset: 69488:784127390130 parent: 69486:8f0c830051ee parent: 69487:28e661ab5453 user: Jesus Cea date: Wed Apr 20 21:01:45 2011 +0200 summary: null merge files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 20 21:14:54 2011 From: python-checkins at python.org (jesus.cea) Date: Wed, 20 Apr 2011 21:14:54 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> 3.2): heads merging Message-ID: http://hg.python.org/cpython/rev/7ed8e898cbdf changeset: 69489:7ed8e898cbdf branch: 3.2 parent: 69487:28e661ab5453 parent: 69479:87f9519203f4 user: Jesus Cea date: Wed Apr 20 21:10:20 2011 +0200 summary: heads merging files: Lib/test/string_tests.py | 14 +++++++------- Lib/test/test_bytes.py | 14 +++++++------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Lib/test/string_tests.py b/Lib/test/string_tests.py --- a/Lib/test/string_tests.py +++ b/Lib/test/string_tests.py @@ -1225,19 +1225,19 @@ # issue 11828 s = 'hello' x = 'x' - self.assertRaisesRegexp(TypeError, r'^find\(', s.find, + self.assertRaisesRegex(TypeError, r'^find\(', s.find, x, None, None, None) - self.assertRaisesRegexp(TypeError, r'^rfind\(', s.rfind, + self.assertRaisesRegex(TypeError, r'^rfind\(', s.rfind, x, None, None, None) - self.assertRaisesRegexp(TypeError, r'^index\(', s.index, + self.assertRaisesRegex(TypeError, r'^index\(', s.index, x, None, None, None) - self.assertRaisesRegexp(TypeError, r'^rindex\(', s.rindex, + self.assertRaisesRegex(TypeError, r'^rindex\(', s.rindex, x, None, None, None) - self.assertRaisesRegexp(TypeError, r'^count\(', s.count, + self.assertRaisesRegex(TypeError, r'^count\(', s.count, x, None, None, None) - self.assertRaisesRegexp(TypeError, r'^startswith\(', s.startswith, + self.assertRaisesRegex(TypeError, r'^startswith\(', s.startswith, x, None, None, None) - self.assertRaisesRegexp(TypeError, r'^endswith\(', s.endswith, + self.assertRaisesRegex(TypeError, r'^endswith\(', s.endswith, x, None, None, None) 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 @@ -523,19 +523,19 @@ # issue 11828 b = self.type2test(b'hello') x = self.type2test(b'x') - self.assertRaisesRegexp(TypeError, r'\bfind\b', b.find, + self.assertRaisesRegex(TypeError, r'\bfind\b', b.find, x, None, None, None) - self.assertRaisesRegexp(TypeError, r'\brfind\b', b.rfind, + self.assertRaisesRegex(TypeError, r'\brfind\b', b.rfind, x, None, None, None) - self.assertRaisesRegexp(TypeError, r'\bindex\b', b.index, + self.assertRaisesRegex(TypeError, r'\bindex\b', b.index, x, None, None, None) - self.assertRaisesRegexp(TypeError, r'\brindex\b', b.rindex, + self.assertRaisesRegex(TypeError, r'\brindex\b', b.rindex, x, None, None, None) - self.assertRaisesRegexp(TypeError, r'\bcount\b', b.count, + self.assertRaisesRegex(TypeError, r'\bcount\b', b.count, x, None, None, None) - self.assertRaisesRegexp(TypeError, r'\bstartswith\b', b.startswith, + self.assertRaisesRegex(TypeError, r'\bstartswith\b', b.startswith, x, None, None, None) - self.assertRaisesRegexp(TypeError, r'\bendswith\b', b.endswith, + self.assertRaisesRegex(TypeError, r'\bendswith\b', b.endswith, x, None, None, None) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 20 21:14:57 2011 From: python-checkins at python.org (jesus.cea) Date: Wed, 20 Apr 2011 21:14:57 +0200 Subject: [Python-checkins] cpython (merge default -> default): heads merging Message-ID: http://hg.python.org/cpython/rev/e6f76169560a changeset: 69490:e6f76169560a parent: 69480:71d4925a1364 parent: 69488:784127390130 user: Jesus Cea date: Wed Apr 20 21:11:52 2011 +0200 summary: heads merging files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 20 21:14:57 2011 From: python-checkins at python.org (jesus.cea) Date: Wed, 20 Apr 2011 21:14:57 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): merge Message-ID: http://hg.python.org/cpython/rev/97ad0da26a24 changeset: 69491:97ad0da26a24 parent: 69490:e6f76169560a parent: 69489:7ed8e898cbdf user: Jesus Cea date: Wed Apr 20 21:13:36 2011 +0200 summary: merge files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 20 22:10:04 2011 From: python-checkins at python.org (raymond.hettinger) Date: Wed, 20 Apr 2011 22:10:04 +0200 Subject: [Python-checkins] cpython (3.1): Minor text rearrangement. Message-ID: http://hg.python.org/cpython/rev/e9979852fc02 changeset: 69492:e9979852fc02 branch: 3.1 parent: 69484:ef95702b555e user: Raymond Hettinger date: Wed Apr 20 13:03:49 2011 -0700 summary: Minor text rearrangement. files: Lib/collections.py | 20 ++++++++++---------- 1 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Lib/collections.py b/Lib/collections.py --- a/Lib/collections.py +++ b/Lib/collections.py @@ -98,16 +98,6 @@ yield curr.key curr = curr.prev - def __reduce__(self): - 'Return state information for pickling' - items = [[k, self[k]] for k in self] - inst_dict = vars(self).copy() - for k in vars(OrderedDict()): - inst_dict.pop(k, None) - if inst_dict: - return (self.__class__, (items,), inst_dict) - return self.__class__, (items,) - update = __update = MutableMapping.update keys = MutableMapping.keys values = MutableMapping.values @@ -156,6 +146,16 @@ self.__in_repr = False return result + def __reduce__(self): + 'Return state information for pickling' + items = [[k, self[k]] for k in self] + inst_dict = vars(self).copy() + for k in vars(OrderedDict()): + inst_dict.pop(k, None) + if inst_dict: + return (self.__class__, (items,), inst_dict) + return self.__class__, (items,) + def copy(self): 'od.copy() -> a shallow copy of od' return self.__class__(self) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 20 22:10:05 2011 From: python-checkins at python.org (raymond.hettinger) Date: Wed, 20 Apr 2011 22:10:05 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): Minor text rearrangement. Message-ID: http://hg.python.org/cpython/rev/235633dbbf9a changeset: 69493:235633dbbf9a branch: 3.2 parent: 69489:7ed8e898cbdf parent: 69492:e9979852fc02 user: Raymond Hettinger date: Wed Apr 20 13:08:40 2011 -0700 summary: Minor text rearrangement. files: Lib/collections.py | 20 ++++++++++---------- 1 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Lib/collections.py b/Lib/collections.py --- a/Lib/collections.py +++ b/Lib/collections.py @@ -151,16 +151,6 @@ link.next = first root.next = first.prev = link - def __reduce__(self): - 'Return state information for pickling' - items = [[k, self[k]] for k in self] - inst_dict = vars(self).copy() - for k in vars(OrderedDict()): - inst_dict.pop(k, None) - if inst_dict: - return (self.__class__, (items,), inst_dict) - return self.__class__, (items,) - def __sizeof__(self): sizeof = _sys.getsizeof n = len(self) + 1 # number of links including root @@ -201,6 +191,16 @@ return '%s()' % (self.__class__.__name__,) return '%s(%r)' % (self.__class__.__name__, list(self.items())) + def __reduce__(self): + 'Return state information for pickling' + items = [[k, self[k]] for k in self] + inst_dict = vars(self).copy() + for k in vars(OrderedDict()): + inst_dict.pop(k, None) + if inst_dict: + return (self.__class__, (items,), inst_dict) + return self.__class__, (items,) + def copy(self): 'od.copy() -> a shallow copy of od' return self.__class__(self) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 20 22:10:05 2011 From: python-checkins at python.org (raymond.hettinger) Date: Wed, 20 Apr 2011 22:10:05 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Minor text rearrangement. Message-ID: http://hg.python.org/cpython/rev/a4b93391fb7c changeset: 69494:a4b93391fb7c parent: 69491:97ad0da26a24 parent: 69493:235633dbbf9a user: Raymond Hettinger date: Wed Apr 20 13:09:46 2011 -0700 summary: Minor text rearrangement. files: Lib/collections/__init__.py | 20 ++++++++++---------- 1 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Lib/collections/__init__.py b/Lib/collections/__init__.py --- a/Lib/collections/__init__.py +++ b/Lib/collections/__init__.py @@ -152,16 +152,6 @@ link.next = first root.next = first.prev = link - def __reduce__(self): - 'Return state information for pickling' - items = [[k, self[k]] for k in self] - inst_dict = vars(self).copy() - for k in vars(OrderedDict()): - inst_dict.pop(k, None) - if inst_dict: - return (self.__class__, (items,), inst_dict) - return self.__class__, (items,) - def __sizeof__(self): sizeof = _sys.getsizeof n = len(self) + 1 # number of links including root @@ -202,6 +192,16 @@ return '%s()' % (self.__class__.__name__,) return '%s(%r)' % (self.__class__.__name__, list(self.items())) + def __reduce__(self): + 'Return state information for pickling' + items = [[k, self[k]] for k in self] + inst_dict = vars(self).copy() + for k in vars(OrderedDict()): + inst_dict.pop(k, None) + if inst_dict: + return (self.__class__, (items,), inst_dict) + return self.__class__, (items,) + def copy(self): 'od.copy() -> a shallow copy of od' return self.__class__(self) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 20 22:11:48 2011 From: python-checkins at python.org (raymond.hettinger) Date: Wed, 20 Apr 2011 22:11:48 +0200 Subject: [Python-checkins] cpython (2.7): Minor text rearrangement. Message-ID: http://hg.python.org/cpython/rev/4a1530e9df7f changeset: 69495:4a1530e9df7f branch: 2.7 parent: 69475:1eaf6b9897eb user: Raymond Hettinger date: Wed Apr 20 13:11:38 2011 -0700 summary: Minor text rearrangement. files: Lib/collections.py | 20 ++++++++++---------- 1 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Lib/collections.py b/Lib/collections.py --- a/Lib/collections.py +++ b/Lib/collections.py @@ -112,16 +112,6 @@ yield curr[KEY] curr = curr[PREV] - def __reduce__(self): - 'Return state information for pickling' - items = [[k, self[k]] for k in self] - inst_dict = vars(self).copy() - for k in vars(OrderedDict()): - inst_dict.pop(k, None) - if inst_dict: - return (self.__class__, (items,), inst_dict) - return self.__class__, (items,) - def clear(self): 'od.clear() -> None. Remove all items from od.' try: @@ -190,6 +180,16 @@ return '%s()' % (self.__class__.__name__,) return '%s(%r)' % (self.__class__.__name__, self.items()) + def __reduce__(self): + 'Return state information for pickling' + items = [[k, self[k]] for k in self] + inst_dict = vars(self).copy() + for k in vars(OrderedDict()): + inst_dict.pop(k, None) + if inst_dict: + return (self.__class__, (items,), inst_dict) + return self.__class__, (items,) + def copy(self): 'od.copy() -> a shallow copy of od' return self.__class__(self) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 20 22:41:44 2011 From: python-checkins at python.org (jesus.cea) Date: Wed, 20 Apr 2011 22:41:44 +0200 Subject: [Python-checkins] cpython (3.1): Port 5b607cd8c71b (closes #11892) Message-ID: http://hg.python.org/cpython/rev/358a0dd0a9f2 changeset: 69496:358a0dd0a9f2 branch: 3.1 parent: 69484:ef95702b555e user: Jesus Cea date: Wed Apr 20 22:26:57 2011 +0200 summary: Port 5b607cd8c71b (closes #11892) files: Include/pyport.h | 4 ++++ Objects/complexobject.c | 4 ---- Objects/floatobject.c | 4 ---- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/Include/pyport.h b/Include/pyport.h --- a/Include/pyport.h +++ b/Include/pyport.h @@ -279,6 +279,10 @@ #include +#ifdef HAVE_IEEEFP_H +#include /* needed for 'finite' declaration on some platforms */ +#endif + #include /* Moved here from the math section, before extern "C" */ /******************************************** diff --git a/Objects/complexobject.c b/Objects/complexobject.c --- a/Objects/complexobject.c +++ b/Objects/complexobject.c @@ -8,10 +8,6 @@ #include "Python.h" #include "structmember.h" -#ifdef HAVE_IEEEFP_H -#include -#endif - #ifndef WITHOUT_COMPLEX /* elementary operations on complex numbers */ diff --git a/Objects/floatobject.c b/Objects/floatobject.c --- a/Objects/floatobject.c +++ b/Objects/floatobject.c @@ -15,10 +15,6 @@ #define MAX(x, y) ((x) < (y) ? (y) : (x)) #define MIN(x, y) ((x) < (y) ? (x) : (y)) -#ifdef HAVE_IEEEFP_H -#include -#endif - #ifdef _OSF_SOURCE /* OSF1 5.1 doesn't make this available with XOPEN_SOURCE_EXTENDED defined */ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 20 22:41:45 2011 From: python-checkins at python.org (jesus.cea) Date: Wed, 20 Apr 2011 22:41:45 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): null merge Message-ID: http://hg.python.org/cpython/rev/7a36136cc01b changeset: 69497:7a36136cc01b branch: 3.2 parent: 69489:7ed8e898cbdf parent: 69496:358a0dd0a9f2 user: Jesus Cea date: Wed Apr 20 22:31:34 2011 +0200 summary: null merge files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 20 22:41:49 2011 From: python-checkins at python.org (jesus.cea) Date: Wed, 20 Apr 2011 22:41:49 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): null merge Message-ID: http://hg.python.org/cpython/rev/0c50e849d455 changeset: 69498:0c50e849d455 parent: 69491:97ad0da26a24 parent: 69497:7a36136cc01b user: Jesus Cea date: Wed Apr 20 22:32:19 2011 +0200 summary: null merge files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 20 22:41:49 2011 From: python-checkins at python.org (jesus.cea) Date: Wed, 20 Apr 2011 22:41:49 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.1): merge heads Message-ID: http://hg.python.org/cpython/rev/b20d3f54366c changeset: 69499:b20d3f54366c branch: 3.1 parent: 69492:e9979852fc02 parent: 69496:358a0dd0a9f2 user: Jesus Cea date: Wed Apr 20 22:38:26 2011 +0200 summary: merge heads files: Include/pyport.h | 4 ++++ Objects/complexobject.c | 4 ---- Objects/floatobject.c | 4 ---- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/Include/pyport.h b/Include/pyport.h --- a/Include/pyport.h +++ b/Include/pyport.h @@ -279,6 +279,10 @@ #include +#ifdef HAVE_IEEEFP_H +#include /* needed for 'finite' declaration on some platforms */ +#endif + #include /* Moved here from the math section, before extern "C" */ /******************************************** diff --git a/Objects/complexobject.c b/Objects/complexobject.c --- a/Objects/complexobject.c +++ b/Objects/complexobject.c @@ -8,10 +8,6 @@ #include "Python.h" #include "structmember.h" -#ifdef HAVE_IEEEFP_H -#include -#endif - #ifndef WITHOUT_COMPLEX /* elementary operations on complex numbers */ diff --git a/Objects/floatobject.c b/Objects/floatobject.c --- a/Objects/floatobject.c +++ b/Objects/floatobject.c @@ -15,10 +15,6 @@ #define MAX(x, y) ((x) < (y) ? (y) : (x)) #define MIN(x, y) ((x) < (y) ? (x) : (y)) -#ifdef HAVE_IEEEFP_H -#include -#endif - #ifdef _OSF_SOURCE /* OSF1 5.1 doesn't make this available with XOPEN_SOURCE_EXTENDED defined */ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 20 22:41:55 2011 From: python-checkins at python.org (jesus.cea) Date: Wed, 20 Apr 2011 22:41:55 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> 3.2): merge heads Message-ID: http://hg.python.org/cpython/rev/d3810c1428ad changeset: 69500:d3810c1428ad branch: 3.2 parent: 69493:235633dbbf9a parent: 69497:7a36136cc01b user: Jesus Cea date: Wed Apr 20 22:39:29 2011 +0200 summary: merge heads files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 20 22:41:56 2011 From: python-checkins at python.org (jesus.cea) Date: Wed, 20 Apr 2011 22:41:56 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): merge Message-ID: http://hg.python.org/cpython/rev/0560f023a28d changeset: 69501:0560f023a28d branch: 3.2 parent: 69500:d3810c1428ad parent: 69499:b20d3f54366c user: Jesus Cea date: Wed Apr 20 22:40:48 2011 +0200 summary: merge files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 20 22:41:57 2011 From: python-checkins at python.org (jesus.cea) Date: Wed, 20 Apr 2011 22:41:57 +0200 Subject: [Python-checkins] cpython (merge default -> default): merge heads Message-ID: http://hg.python.org/cpython/rev/422ff0f6a49f changeset: 69502:422ff0f6a49f parent: 69494:a4b93391fb7c parent: 69498:0c50e849d455 user: Jesus Cea date: Wed Apr 20 22:41:21 2011 +0200 summary: merge heads files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 20 22:41:59 2011 From: python-checkins at python.org (jesus.cea) Date: Wed, 20 Apr 2011 22:41:59 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): merge Message-ID: http://hg.python.org/cpython/rev/dcd2a466a0c8 changeset: 69503:dcd2a466a0c8 parent: 69502:422ff0f6a49f parent: 69501:0560f023a28d user: Jesus Cea date: Wed Apr 20 22:41:39 2011 +0200 summary: merge files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 20 23:25:39 2011 From: python-checkins at python.org (victor.stinner) Date: Wed, 20 Apr 2011 23:25:39 +0200 Subject: [Python-checkins] cpython: Simplify _count_elements() in _collections Message-ID: http://hg.python.org/cpython/rev/4bd68b1f8702 changeset: 69504:4bd68b1f8702 user: Victor Stinner date: Wed Apr 20 23:23:52 2011 +0200 summary: Simplify _count_elements() in _collections PyIter_Next() cannot return a PyExc_StopIteration: it clears this exception. files: Modules/_collectionsmodule.c | 16 ++++------------ 1 files changed, 4 insertions(+), 12 deletions(-) diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -1552,12 +1552,8 @@ if (PyDict_CheckExact(mapping)) { while (1) { key = PyIter_Next(it); - if (key == NULL) { - if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_StopIteration)) - PyErr_Clear(); - else - break; - } + if (key == NULL) + break; oldval = PyDict_GetItem(mapping, key); if (oldval == NULL) { if (PyDict_SetItem(mapping, key, one) == -1) @@ -1575,12 +1571,8 @@ } else { while (1) { key = PyIter_Next(it); - if (key == NULL) { - if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_StopIteration)) - PyErr_Clear(); - else - break; - } + if (key == NULL) + break; oldval = PyObject_GetItem(mapping, key); if (oldval == NULL) { if (!PyErr_Occurred() || !PyErr_ExceptionMatches(PyExc_KeyError)) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Apr 21 01:27:20 2011 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 21 Apr 2011 01:27:20 +0200 Subject: [Python-checkins] cpython: glossary entry for struct sequence Message-ID: http://hg.python.org/cpython/rev/8951c60b9005 changeset: 69505:8951c60b9005 user: Benjamin Peterson date: Wed Apr 20 18:27:32 2011 -0500 summary: glossary entry for struct sequence files: Doc/glossary.rst | 8 ++++++++ 1 files changed, 8 insertions(+), 0 deletions(-) diff --git a/Doc/glossary.rst b/Doc/glossary.rst --- a/Doc/glossary.rst +++ b/Doc/glossary.rst @@ -580,6 +580,14 @@ an :term:`expression` or a one of several constructs with a keyword, such as :keyword:`if`, :keyword:`while` or :keyword:`for`. + struct sequence + A tuple with named elements. Struct sequences expose an interface similiar + to :term:`named tuple` in that elements can either be accessed either by + index or as an attribute. However, they do not have any of the named tuple + methods like :meth:`~collections.somenamedtuple._make` or + :meth:`~collections.somenamedtuple._asdict`. Examples of struct sequences + include :data:`sys.float_info` and the return value of :func:`os.stat`. + triple-quoted string A string which is bound by three instances of either a quotation mark (") or an apostrophe ('). While they don't provide any functionality -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Apr 21 01:31:08 2011 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 21 Apr 2011 01:31:08 +0200 Subject: [Python-checkins] cpython: say struct sequence rather than structseq and link to glossary Message-ID: http://hg.python.org/cpython/rev/96e0e79d33de changeset: 69506:96e0e79d33de user: Benjamin Peterson date: Wed Apr 20 18:31:22 2011 -0500 summary: say struct sequence rather than structseq and link to glossary files: Doc/library/sys.rst | 25 +++++++++++++------------ 1 files changed, 13 insertions(+), 12 deletions(-) diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -224,8 +224,8 @@ .. data:: flags - The struct sequence *flags* exposes the status of command line flags. The - attributes are read only. + The :term:`struct sequence` *flags* exposes the status of command line + flags. The attributes are read only. ============================= ============================= attribute flag @@ -249,12 +249,12 @@ .. data:: float_info - A structseq holding information about the float type. It contains low level - information about the precision and internal representation. The values - correspond to the various floating-point constants defined in the standard - header file :file:`float.h` for the 'C' programming language; see section - 5.2.4.2.2 of the 1999 ISO/IEC C standard [C99]_, 'Characteristics of - floating types', for details. + A :term:`struct sequence` holding information about the float type. It + contains low level information about the precision and internal + representation. The values correspond to the various floating-point + constants defined in the standard header file :file:`float.h` for the 'C' + programming language; see section 5.2.4.2.2 of the 1999 ISO/IEC C standard + [C99]_, 'Characteristics of floating types', for details. +---------------------+----------------+--------------------------------------------------+ | attribute | float.h macro | explanation | @@ -500,8 +500,9 @@ .. data:: hash_info - A structseq giving parameters of the numeric hash implementation. For - more details about hashing of numeric types, see :ref:`numeric-hash`. + A :term:`struct sequence` giving parameters of the numeric hash + implementation. For more details about hashing of numeric types, see + :ref:`numeric-hash`. +---------------------+--------------------------------------------------+ | attribute | explanation | @@ -542,8 +543,8 @@ .. data:: int_info - A struct sequence that holds information about Python's - internal representation of integers. The attributes are read only. + A :term:`struct sequence` that holds information about Python's internal + representation of integers. The attributes are read only. +-------------------------+----------------------------------------------+ | attribute | explanation | -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Thu Apr 21 05:00:00 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Thu, 21 Apr 2011 05:00:00 +0200 Subject: [Python-checkins] Daily reference leaks (96e0e79d33de): sum=-323 Message-ID: results for 96e0e79d33de on branch "default" -------------------------------------------- test_pydoc leaked [0, 0, -323] references, sum=-323 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflog8o8caE', '-x'] From python-checkins at python.org Thu Apr 21 13:50:32 2011 From: python-checkins at python.org (ezio.melotti) Date: Thu, 21 Apr 2011 13:50:32 +0200 Subject: [Python-checkins] cpython (3.2): #11897: Fix typo in porting howto. Patch by Marti Raudsepp. Message-ID: http://hg.python.org/cpython/rev/05a7d3048c49 changeset: 69507:05a7d3048c49 branch: 3.2 parent: 69501:0560f023a28d user: Ezio Melotti date: Thu Apr 21 14:49:03 2011 +0300 summary: #11897: Fix typo in porting howto. Patch by Marti Raudsepp. files: Doc/howto/pyporting.rst | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/howto/pyporting.rst b/Doc/howto/pyporting.rst --- a/Doc/howto/pyporting.rst +++ b/Doc/howto/pyporting.rst @@ -247,8 +247,8 @@ Python that you can utilize. -``from __future__ import absolute_imports`` -''''''''''''''''''''''''''''''''''''''''''' +``from __future__ import absolute_import`` +'''''''''''''''''''''''''''''''''''''''''' Implicit relative imports (e.g., importing ``spam.bacon`` from within ``spam.eggs`` with the statement ``import bacon``) does not work in Python 3. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Apr 21 13:50:33 2011 From: python-checkins at python.org (ezio.melotti) Date: Thu, 21 Apr 2011 13:50:33 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): #11897: Merge with 3.2. Message-ID: http://hg.python.org/cpython/rev/968fba3f34b3 changeset: 69508:968fba3f34b3 parent: 69506:96e0e79d33de parent: 69507:05a7d3048c49 user: Ezio Melotti date: Thu Apr 21 14:49:56 2011 +0300 summary: #11897: Merge with 3.2. files: Doc/howto/pyporting.rst | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/howto/pyporting.rst b/Doc/howto/pyporting.rst --- a/Doc/howto/pyporting.rst +++ b/Doc/howto/pyporting.rst @@ -247,8 +247,8 @@ Python that you can utilize. -``from __future__ import absolute_imports`` -''''''''''''''''''''''''''''''''''''''''''' +``from __future__ import absolute_import`` +'''''''''''''''''''''''''''''''''''''''''' Implicit relative imports (e.g., importing ``spam.bacon`` from within ``spam.eggs`` with the statement ``import bacon``) does not work in Python 3. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Apr 21 14:29:41 2011 From: python-checkins at python.org (ezio.melotti) Date: Thu, 21 Apr 2011 14:29:41 +0200 Subject: [Python-checkins] cpython (2.7): #11885: capitalize Python. Message-ID: http://hg.python.org/cpython/rev/0f084f150198 changeset: 69509:0f084f150198 branch: 2.7 parent: 69495:4a1530e9df7f user: Ezio Melotti date: Thu Apr 21 15:26:46 2011 +0300 summary: #11885: capitalize Python. files: Doc/library/argparse.rst | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -75,7 +75,7 @@ >>> parser = argparse.ArgumentParser(description='Process some integers.') The :class:`ArgumentParser` object will hold all the information necessary to -parse the command line into python data types. +parse the command line into Python data types. Adding arguments @@ -1784,7 +1784,7 @@ :exc:`ArgumentError`. * Replace strings with implicit arguments such as ``%default`` or ``%prog`` with - the standard python syntax to use dictionaries to format strings, that is, + the standard Python syntax to use dictionaries to format strings, that is, ``%(default)s`` and ``%(prog)s``. * Replace the OptionParser constructor ``version`` argument with a call to -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Apr 21 14:29:41 2011 From: python-checkins at python.org (ezio.melotti) Date: Thu, 21 Apr 2011 14:29:41 +0200 Subject: [Python-checkins] cpython (3.2): #11885: capitalize Python. Message-ID: http://hg.python.org/cpython/rev/fb6affc7b973 changeset: 69510:fb6affc7b973 branch: 3.2 parent: 69507:05a7d3048c49 user: Ezio Melotti date: Thu Apr 21 15:26:46 2011 +0300 summary: #11885: capitalize Python. files: Doc/library/argparse.rst | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -79,7 +79,7 @@ >>> parser = argparse.ArgumentParser(description='Process some integers.') The :class:`ArgumentParser` object will hold all the information necessary to -parse the command line into python data types. +parse the command line into Python data types. Adding arguments @@ -1797,7 +1797,7 @@ :exc:`ArgumentError`. * Replace strings with implicit arguments such as ``%default`` or ``%prog`` with - the standard python syntax to use dictionaries to format strings, that is, + the standard Python syntax to use dictionaries to format strings, that is, ``%(default)s`` and ``%(prog)s``. * Replace the OptionParser constructor ``version`` argument with a call to -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Apr 21 14:29:45 2011 From: python-checkins at python.org (ezio.melotti) Date: Thu, 21 Apr 2011 14:29:45 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): #11885: Merge with 3.2. Message-ID: http://hg.python.org/cpython/rev/9fece8c3a1a9 changeset: 69511:9fece8c3a1a9 parent: 69508:968fba3f34b3 parent: 69510:fb6affc7b973 user: Ezio Melotti date: Thu Apr 21 15:29:04 2011 +0300 summary: #11885: Merge with 3.2. files: Doc/library/argparse.rst | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -79,7 +79,7 @@ >>> parser = argparse.ArgumentParser(description='Process some integers.') The :class:`ArgumentParser` object will hold all the information necessary to -parse the command line into python data types. +parse the command line into Python data types. Adding arguments @@ -1813,7 +1813,7 @@ :exc:`ArgumentError`. * Replace strings with implicit arguments such as ``%default`` or ``%prog`` with - the standard python syntax to use dictionaries to format strings, that is, + the standard Python syntax to use dictionaries to format strings, that is, ``%(default)s`` and ``%(prog)s``. * Replace the OptionParser constructor ``version`` argument with a call to -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Apr 21 15:14:21 2011 From: python-checkins at python.org (ezio.melotti) Date: Thu, 21 Apr 2011 15:14:21 +0200 Subject: [Python-checkins] cpython (2.7): Add the :mod: role where it was missing. Message-ID: http://hg.python.org/cpython/rev/6f27baeecf4c changeset: 69512:6f27baeecf4c branch: 2.7 parent: 69509:0f084f150198 user: Ezio Melotti date: Thu Apr 21 16:12:17 2011 +0300 summary: Add the :mod: role where it was missing. files: Doc/library/argparse.rst | 22 +++++++++++----------- 1 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -977,7 +977,7 @@ required ^^^^^^^^ -In general, the argparse module assumes that flags like ``-f`` and ``--bar`` +In general, the :mod:`argparse` module assumes that flags like ``-f`` and ``--bar`` indicate *optional* arguments, which can always be omitted at the command line. To make an option *required*, ``True`` can be specified for the ``required=`` keyword argument to :meth:`add_argument`:: @@ -1587,9 +1587,9 @@ .. method:: add_mutually_exclusive_group(required=False) - Create a mutually exclusive group. argparse will make sure that only one of - the arguments in the mutually exclusive group was present on the command - line:: + Create a mutually exclusive group. :mod:`argparse` will make sure that only + one of the arguments in the mutually exclusive group was present on the + command line:: >>> parser = argparse.ArgumentParser(prog='PROG') >>> group = parser.add_mutually_exclusive_group() @@ -1757,14 +1757,14 @@ Upgrading optparse code ----------------------- -Originally, the argparse module had attempted to maintain compatibility with -optparse. However, optparse was difficult to extend transparently, particularly -with the changes required to support the new ``nargs=`` specifiers and better -usage messages. When most everything in optparse had either been copy-pasted -over or monkey-patched, it no longer seemed practical to try to maintain the -backwards compatibility. +Originally, the mod:`argparse` module had attempted to maintain compatibility +with :mod:`optparse`. However, :mod:`optparse` was difficult to extend +transparently, particularly with the changes required to support the new +``nargs=`` specifiers and better usage messages. When most everything in +:mod:`optparse` had either been copy-pasted over or monkey-patched, it no +longer seemed practical to try to maintain the backwards compatibility. -A partial upgrade path from optparse to argparse: +A partial upgrade path from :mod:`optparse` to :mod:`argparse`: * Replace all ``add_option()`` calls with :meth:`ArgumentParser.add_argument` calls. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Apr 21 15:14:22 2011 From: python-checkins at python.org (ezio.melotti) Date: Thu, 21 Apr 2011 15:14:22 +0200 Subject: [Python-checkins] cpython (3.2): Add the :mod: role where it was missing. Message-ID: http://hg.python.org/cpython/rev/498f8b79a93f changeset: 69513:498f8b79a93f branch: 3.2 parent: 69510:fb6affc7b973 user: Ezio Melotti date: Thu Apr 21 16:12:17 2011 +0300 summary: Add the :mod: role where it was missing. files: Doc/library/argparse.rst | 22 +++++++++++----------- 1 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -981,7 +981,7 @@ required ^^^^^^^^ -In general, the argparse module assumes that flags like ``-f`` and ``--bar`` +In general, the :mod:`argparse` module assumes that flags like ``-f`` and ``--bar`` indicate *optional* arguments, which can always be omitted at the command line. To make an option *required*, ``True`` can be specified for the ``required=`` keyword argument to :meth:`add_argument`:: @@ -1601,9 +1601,9 @@ .. method:: add_mutually_exclusive_group(required=False) - Create a mutually exclusive group. argparse will make sure that only one of - the arguments in the mutually exclusive group was present on the command - line:: + Create a mutually exclusive group. :mod:`argparse` will make sure that only + one of the arguments in the mutually exclusive group was present on the + command line:: >>> parser = argparse.ArgumentParser(prog='PROG') >>> group = parser.add_mutually_exclusive_group() @@ -1770,14 +1770,14 @@ Upgrading optparse code ----------------------- -Originally, the argparse module had attempted to maintain compatibility with -optparse. However, optparse was difficult to extend transparently, particularly -with the changes required to support the new ``nargs=`` specifiers and better -usage messages. When most everything in optparse had either been copy-pasted -over or monkey-patched, it no longer seemed practical to try to maintain the -backwards compatibility. +Originally, the mod:`argparse` module had attempted to maintain compatibility +with :mod:`optparse`. However, :mod:`optparse` was difficult to extend +transparently, particularly with the changes required to support the new +``nargs=`` specifiers and better usage messages. When most everything in +:mod:`optparse` had either been copy-pasted over or monkey-patched, it no +longer seemed practical to try to maintain the backwards compatibility. -A partial upgrade path from optparse to argparse: +A partial upgrade path from :mod:`optparse` to :mod:`argparse`: * Replace all ``add_option()`` calls with :meth:`ArgumentParser.add_argument` calls. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Apr 21 15:14:23 2011 From: python-checkins at python.org (ezio.melotti) Date: Thu, 21 Apr 2011 15:14:23 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge with 3.2. Message-ID: http://hg.python.org/cpython/rev/a7b60894bf51 changeset: 69514:a7b60894bf51 parent: 69511:9fece8c3a1a9 parent: 69513:498f8b79a93f user: Ezio Melotti date: Thu Apr 21 16:13:44 2011 +0300 summary: Merge with 3.2. files: Doc/library/argparse.rst | 22 +++++++++++----------- 1 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -997,7 +997,7 @@ required ^^^^^^^^ -In general, the argparse module assumes that flags like ``-f`` and ``--bar`` +In general, the :mod:`argparse` module assumes that flags like ``-f`` and ``--bar`` indicate *optional* arguments, which can always be omitted at the command line. To make an option *required*, ``True`` can be specified for the ``required=`` keyword argument to :meth:`add_argument`:: @@ -1617,9 +1617,9 @@ .. method:: add_mutually_exclusive_group(required=False) - Create a mutually exclusive group. argparse will make sure that only one of - the arguments in the mutually exclusive group was present on the command - line:: + Create a mutually exclusive group. :mod:`argparse` will make sure that only + one of the arguments in the mutually exclusive group was present on the + command line:: >>> parser = argparse.ArgumentParser(prog='PROG') >>> group = parser.add_mutually_exclusive_group() @@ -1786,14 +1786,14 @@ Upgrading optparse code ----------------------- -Originally, the argparse module had attempted to maintain compatibility with -optparse. However, optparse was difficult to extend transparently, particularly -with the changes required to support the new ``nargs=`` specifiers and better -usage messages. When most everything in optparse had either been copy-pasted -over or monkey-patched, it no longer seemed practical to try to maintain the -backwards compatibility. +Originally, the mod:`argparse` module had attempted to maintain compatibility +with :mod:`optparse`. However, :mod:`optparse` was difficult to extend +transparently, particularly with the changes required to support the new +``nargs=`` specifiers and better usage messages. When most everything in +:mod:`optparse` had either been copy-pasted over or monkey-patched, it no +longer seemed practical to try to maintain the backwards compatibility. -A partial upgrade path from optparse to argparse: +A partial upgrade path from :mod:`optparse` to :mod:`argparse`: * Replace all ``add_option()`` calls with :meth:`ArgumentParser.add_argument` calls. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Apr 21 20:09:38 2011 From: python-checkins at python.org (raymond.hettinger) Date: Thu, 21 Apr 2011 20:09:38 +0200 Subject: [Python-checkins] cpython: Add another example for accumulate(). Message-ID: http://hg.python.org/cpython/rev/e8d8c735f3e2 changeset: 69515:e8d8c735f3e2 user: Raymond Hettinger date: Thu Apr 21 11:09:28 2011 -0700 summary: Add another example for accumulate(). files: Doc/library/itertools.rst | 21 ++++++++++++++++++--- 1 files changed, 18 insertions(+), 3 deletions(-) diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -104,9 +104,13 @@ total = func(total, element) yield total - Uses for the *func* argument include :func:`min` for a running minimum, - :func:`max` for a running maximum, and :func:`operator.mul` for a running - product:: + There are a number of uses for the *func* argument. It can be set to + :func:`min` for a running minimum, :func:`max` for a running maximum, or + :func:`operator.mul` for a running product. Amortization tables can be + built by accumulating interest and applying payments. First-order + `recurrence relations `_ + can be modeled by supplying the initial value in the iterable and using only + the accumulated total in *func* argument:: >>> data = [3, 4, 6, 2, 1, 9, 0, 7, 5, 8] >>> list(accumulate(data, operator.mul)) # running product @@ -119,6 +123,17 @@ >>> list(accumulate(cashflows, lambda bal, pmt: bal*1.05 + pmt)) [1000, 960.0, 918.0, 873.9000000000001, 827.5950000000001] + # Chaotic recurrence relation http://en.wikipedia.org/wiki/Logistic_map + >>> logistic_map = lambda x, _: r * x * (1 - x) + >>> r = 3.8 + >>> x0 = 0.4 + >>> inputs = repeat(x0, 36) # only the initial value is used + >>> [format(x, '.2f') for x in accumulate(inputs, logistic_map)] + ['0.40', '0.91', '0.30', '0.81', '0.60', '0.92', '0.29', '0.79', '0.63', + '0.88' ,'0.39', '0.90', '0.33', '0.84', '0.52', '0.95', '0.18', '0.57', + '0.93', '0.25', '0.71', '0.79', '0.63', '0.88', '0.39', '0.91', '0.32', + '0.83', '0.54', '0.95', '0.20', '0.60', '0.91', '0.30', '0.80', '0.60'] + .. versionadded:: 3.2 .. versionchanged:: 3.3 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Apr 21 21:59:20 2011 From: python-checkins at python.org (ezio.melotti) Date: Thu, 21 Apr 2011 21:59:20 +0200 Subject: [Python-checkins] cpython (2.7): #11902: Fix typo in argparse doc. Noticed by Vladimir Rutsky. Message-ID: http://hg.python.org/cpython/rev/e8464256b4d7 changeset: 69516:e8464256b4d7 branch: 2.7 parent: 69512:6f27baeecf4c user: Ezio Melotti date: Thu Apr 21 22:56:51 2011 +0300 summary: #11902: Fix typo in argparse doc. Noticed by Vladimir Rutsky. files: Doc/library/argparse.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -745,7 +745,7 @@ ArgumentParser objects usually associate a single command-line argument with a single action to be taken. The ``nargs`` keyword argument associates a -different number of command-line arguments with a single action.. The supported +different number of command-line arguments with a single action. The supported values are: * N (an integer). N args from the command line will be gathered together into a -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Apr 21 21:59:21 2011 From: python-checkins at python.org (ezio.melotti) Date: Thu, 21 Apr 2011 21:59:21 +0200 Subject: [Python-checkins] cpython (3.2): #11902: Fix typo in argparse doc. Noticed by Vladimir Rutsky. Message-ID: http://hg.python.org/cpython/rev/88df1ef4eec8 changeset: 69517:88df1ef4eec8 branch: 3.2 parent: 69513:498f8b79a93f user: Ezio Melotti date: Thu Apr 21 22:56:51 2011 +0300 summary: #11902: Fix typo in argparse doc. Noticed by Vladimir Rutsky. files: Doc/library/argparse.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -749,7 +749,7 @@ ArgumentParser objects usually associate a single command-line argument with a single action to be taken. The ``nargs`` keyword argument associates a -different number of command-line arguments with a single action.. The supported +different number of command-line arguments with a single action. The supported values are: * N (an integer). N args from the command line will be gathered together into a -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Apr 21 21:59:28 2011 From: python-checkins at python.org (ezio.melotti) Date: Thu, 21 Apr 2011 21:59:28 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): #11902: Merge with 3.2. Message-ID: http://hg.python.org/cpython/rev/56825d54dc84 changeset: 69518:56825d54dc84 parent: 69515:e8d8c735f3e2 parent: 69517:88df1ef4eec8 user: Ezio Melotti date: Thu Apr 21 22:58:40 2011 +0300 summary: #11902: Merge with 3.2. files: Doc/library/argparse.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -765,7 +765,7 @@ ArgumentParser objects usually associate a single command-line argument with a single action to be taken. The ``nargs`` keyword argument associates a -different number of command-line arguments with a single action.. The supported +different number of command-line arguments with a single action. The supported values are: * N (an integer). N args from the command line will be gathered together into a -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Apr 21 22:13:33 2011 From: python-checkins at python.org (ezio.melotti) Date: Thu, 21 Apr 2011 22:13:33 +0200 Subject: [Python-checkins] cpython (2.7): #11904: fix indentation in argparse doc. Noticed by Vladimir Rutsky. Message-ID: http://hg.python.org/cpython/rev/79f3ae389dae changeset: 69519:79f3ae389dae branch: 2.7 parent: 69516:e8464256b4d7 user: Ezio Melotti date: Thu Apr 21 23:06:48 2011 +0300 summary: #11904: fix indentation in argparse doc. Noticed by Vladimir Rutsky. files: Doc/library/argparse.rst | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -647,7 +647,7 @@ command-line args should be handled. The supported actions are: * ``'store'`` - This just stores the argument's value. This is the default - action. For example:: + action. For example:: >>> parser = argparse.ArgumentParser() >>> parser.add_argument('--foo') @@ -655,9 +655,9 @@ Namespace(foo='1') * ``'store_const'`` - This stores the value specified by the const_ keyword - argument. (Note that the const_ keyword argument defaults to the rather - unhelpful ``None``.) The ``'store_const'`` action is most commonly used with - optional arguments that specify some sort of flag. For example:: + argument. (Note that the const_ keyword argument defaults to the rather + unhelpful ``None``.) The ``'store_const'`` action is most commonly used with + optional arguments that specify some sort of flag. For example:: >>> parser = argparse.ArgumentParser() >>> parser.add_argument('--foo', action='store_const', const=42) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Apr 21 22:13:34 2011 From: python-checkins at python.org (ezio.melotti) Date: Thu, 21 Apr 2011 22:13:34 +0200 Subject: [Python-checkins] cpython (2.7): #11905: fix missing full stop in argparse doc. Noticed by Vladimir Rutsky. Message-ID: http://hg.python.org/cpython/rev/f6ea7abc4eb2 changeset: 69520:f6ea7abc4eb2 branch: 2.7 user: Ezio Melotti date: Thu Apr 21 23:09:27 2011 +0300 summary: #11905: fix missing full stop in argparse doc. Noticed by Vladimir Rutsky. files: Doc/library/argparse.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -578,7 +578,7 @@ has its own more detailed description below, but in short they are: * `name or flags`_ - Either a name or a list of option strings, e.g. ``foo`` - or ``-f, --foo`` + or ``-f, --foo``. * action_ - The basic type of action to be taken when this argument is encountered at the command line. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Apr 21 22:13:37 2011 From: python-checkins at python.org (ezio.melotti) Date: Thu, 21 Apr 2011 22:13:37 +0200 Subject: [Python-checkins] cpython (3.2): #11904: fix indentation in argparse doc. Noticed by Vladimir Rutsky. Message-ID: http://hg.python.org/cpython/rev/473fada5f1b7 changeset: 69521:473fada5f1b7 branch: 3.2 parent: 69517:88df1ef4eec8 user: Ezio Melotti date: Thu Apr 21 23:06:48 2011 +0300 summary: #11904: fix indentation in argparse doc. Noticed by Vladimir Rutsky. files: Doc/library/argparse.rst | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -651,7 +651,7 @@ command-line args should be handled. The supported actions are: * ``'store'`` - This just stores the argument's value. This is the default - action. For example:: + action. For example:: >>> parser = argparse.ArgumentParser() >>> parser.add_argument('--foo') @@ -659,9 +659,9 @@ Namespace(foo='1') * ``'store_const'`` - This stores the value specified by the const_ keyword - argument. (Note that the const_ keyword argument defaults to the rather - unhelpful ``None``.) The ``'store_const'`` action is most commonly used with - optional arguments that specify some sort of flag. For example:: + argument. (Note that the const_ keyword argument defaults to the rather + unhelpful ``None``.) The ``'store_const'`` action is most commonly used with + optional arguments that specify some sort of flag. For example:: >>> parser = argparse.ArgumentParser() >>> parser.add_argument('--foo', action='store_const', const=42) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Apr 21 22:13:44 2011 From: python-checkins at python.org (ezio.melotti) Date: Thu, 21 Apr 2011 22:13:44 +0200 Subject: [Python-checkins] cpython (3.2): #11905: fix missing full stop in argparse doc. Noticed by Vladimir Rutsky. Message-ID: http://hg.python.org/cpython/rev/15f482996880 changeset: 69522:15f482996880 branch: 3.2 user: Ezio Melotti date: Thu Apr 21 23:09:27 2011 +0300 summary: #11905: fix missing full stop in argparse doc. Noticed by Vladimir Rutsky. files: Doc/library/argparse.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -582,7 +582,7 @@ has its own more detailed description below, but in short they are: * `name or flags`_ - Either a name or a list of option strings, e.g. ``foo`` - or ``-f, --foo`` + or ``-f, --foo``. * action_ - The basic type of action to be taken when this argument is encountered at the command line. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Apr 21 22:13:47 2011 From: python-checkins at python.org (ezio.melotti) Date: Thu, 21 Apr 2011 22:13:47 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): #11904-#11905: Merge typo fixes with 3.2. Message-ID: http://hg.python.org/cpython/rev/8568762381b4 changeset: 69523:8568762381b4 parent: 69518:56825d54dc84 parent: 69522:15f482996880 user: Ezio Melotti date: Thu Apr 21 23:12:53 2011 +0300 summary: #11904-#11905: Merge typo fixes with 3.2. files: Doc/library/argparse.rst | 10 +++++----- 1 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -598,7 +598,7 @@ has its own more detailed description below, but in short they are: * `name or flags`_ - Either a name or a list of option strings, e.g. ``foo`` - or ``-f, --foo`` + or ``-f, --foo``. * action_ - The basic type of action to be taken when this argument is encountered at the command line. @@ -667,7 +667,7 @@ command-line args should be handled. The supported actions are: * ``'store'`` - This just stores the argument's value. This is the default - action. For example:: + action. For example:: >>> parser = argparse.ArgumentParser() >>> parser.add_argument('--foo') @@ -675,9 +675,9 @@ Namespace(foo='1') * ``'store_const'`` - This stores the value specified by the const_ keyword - argument. (Note that the const_ keyword argument defaults to the rather - unhelpful ``None``.) The ``'store_const'`` action is most commonly used with - optional arguments that specify some sort of flag. For example:: + argument. (Note that the const_ keyword argument defaults to the rather + unhelpful ``None``.) The ``'store_const'`` action is most commonly used with + optional arguments that specify some sort of flag. For example:: >>> parser = argparse.ArgumentParser() >>> parser.add_argument('--foo', action='store_const', const=42) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Apr 21 22:31:12 2011 From: python-checkins at python.org (ezio.melotti) Date: Thu, 21 Apr 2011 22:31:12 +0200 Subject: [Python-checkins] cpython (2.7): The \ is not supported in Sphinx 0.6. Message-ID: http://hg.python.org/cpython/rev/ba32a7f67b6c changeset: 69524:ba32a7f67b6c branch: 2.7 parent: 69520:f6ea7abc4eb2 user: Ezio Melotti date: Thu Apr 21 23:30:27 2011 +0300 summary: The \ is not supported in Sphinx 0.6. files: Doc/library/argparse.rst | 8 ++------ 1 files changed, 2 insertions(+), 6 deletions(-) diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -120,9 +120,7 @@ ArgumentParser objects ---------------------- -.. class:: ArgumentParser([description], [epilog], [prog], [usage], [add_help], \ - [argument_default], [parents], [prefix_chars], \ - [conflict_handler], [formatter_class]) +.. class:: ArgumentParser([description], [epilog], [prog], [usage], [add_help], [argument_default], [parents], [prefix_chars], [conflict_handler], [formatter_class]) Create a new :class:`ArgumentParser` object. Each parameter has its own more detailed description below, but in short they are: @@ -570,9 +568,7 @@ The add_argument() method ------------------------- -.. method:: ArgumentParser.add_argument(name or flags..., [action], [nargs], \ - [const], [default], [type], [choices], [required], \ - [help], [metavar], [dest]) +.. method:: ArgumentParser.add_argument(name or flags..., [action], [nargs], [const], [default], [type], [choices], [required], [help], [metavar], [dest]) Define how a single command-line argument should be parsed. Each parameter has its own more detailed description below, but in short they are: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 22 00:58:28 2011 From: python-checkins at python.org (ezio.melotti) Date: Fri, 22 Apr 2011 00:58:28 +0200 Subject: [Python-checkins] cpython (2.7): Fix some more markup glitches in argparse doc. Message-ID: http://hg.python.org/cpython/rev/c821d3d335e8 changeset: 69525:c821d3d335e8 branch: 2.7 user: Ezio Melotti date: Fri Apr 22 01:29:13 2011 +0300 summary: Fix some more markup glitches in argparse doc. files: Doc/library/argparse.rst | 208 ++++++++++++++------------ 1 files changed, 110 insertions(+), 98 deletions(-) diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -93,7 +93,7 @@ ... const=sum, default=max, ... help='sum the integers (default: find the max)') -Later, calling :meth:`parse_args` will return an object with +Later, calling :meth:`~ArgumentParser.parse_args` will return an object with two attributes, ``integers`` and ``accumulate``. The ``integers`` attribute will be a list of one or more ints, and the ``accumulate`` attribute will be either the :func:`sum` function, if ``--sum`` was specified at the command line, @@ -289,10 +289,10 @@ Namespace(f='bar') Arguments read from a file must by default be one per line (but see also -:meth:`convert_arg_line_to_args`) and are treated as if they were in the same -place as the original file referencing argument on the command line. So in the -example above, the expression ``['-f', 'foo', '@args.txt']`` is considered -equivalent to the expression ``['-f', 'foo', '-f', 'bar']``. +:meth:`~ArgumentParser.convert_arg_line_to_args`) and are treated as if they +were in the same place as the original file referencing argument on the command +line. So in the example above, the expression ``['-f', 'foo', '@args.txt']`` +is considered equivalent to the expression ``['-f', 'foo', '-f', 'bar']``. The ``fromfile_prefix_chars=`` argument defaults to ``None``, meaning that arguments will never be treated as file references. @@ -302,11 +302,12 @@ ^^^^^^^^^^^^^^^^ Generally, argument defaults are specified either by passing a default to -:meth:`add_argument` or by calling the :meth:`set_defaults` methods with a -specific set of name-value pairs. Sometimes however, it may be useful to -specify a single parser-wide default for arguments. This can be accomplished by -passing the ``argument_default=`` keyword argument to :class:`ArgumentParser`. -For example, to globally suppress attribute creation on :meth:`parse_args` +:meth:`~ArgumentParser.add_argument` or by calling the +:meth:`~ArgumentParser.set_defaults` methods with a specific set of name-value +pairs. Sometimes however, it may be useful to specify a single parser-wide +default for arguments. This can be accomplished by passing the +``argument_default=`` keyword argument to :class:`ArgumentParser`. For example, +to globally suppress attribute creation on :meth:`~ArgumentParser.parse_args` calls, we supply ``argument_default=SUPPRESS``:: >>> parser = argparse.ArgumentParser(argument_default=argparse.SUPPRESS) @@ -356,11 +357,14 @@ :class:`ArgumentParser` objects allow the help formatting to be customized by specifying an alternate formatting class. Currently, there are three such -classes: :class:`argparse.RawDescriptionHelpFormatter`, -:class:`argparse.RawTextHelpFormatter` and -:class:`argparse.ArgumentDefaultsHelpFormatter`. The first two allow more -control over how textual descriptions are displayed, while the last -automatically adds information about argument default values. +classes: + +.. class:: RawDescriptionHelpFormatter + RawTextHelpFormatter + ArgumentDefaultsHelpFormatter + +The first two allow more control over how textual descriptions are displayed, +while the last automatically adds information about argument default values. By default, :class:`ArgumentParser` objects line-wrap the description_ and epilog_ texts in command-line help messages:: @@ -385,7 +389,7 @@ likewise for this epilog whose whitespace will be cleaned up and whose words will be wrapped across a couple lines -Passing :class:`argparse.RawDescriptionHelpFormatter` as ``formatter_class=`` +Passing :class:`~argparse.RawDescriptionHelpFormatter` as ``formatter_class=`` indicates that description_ and epilog_ are already correctly formatted and should not be line-wrapped:: @@ -606,11 +610,12 @@ name or flags ^^^^^^^^^^^^^ -The :meth:`add_argument` method must know whether an optional argument, like -``-f`` or ``--foo``, or a positional argument, like a list of filenames, is -expected. The first arguments passed to :meth:`add_argument` must therefore be -either a series of flags, or a simple argument name. For example, an optional -argument could be created like:: +The :meth:`~ArgumentParser.add_argument` method must know whether an optional +argument, like ``-f`` or ``--foo``, or a positional argument, like a list of +filenames, is expected. The first arguments passed to +:meth:`~ArgumentParser.add_argument` must therefore be either a series of +flags, or a simple argument name. For example, an optional argument could +be created like:: >>> parser.add_argument('-f', '--foo') @@ -618,8 +623,9 @@ >>> parser.add_argument('bar') -When :meth:`parse_args` is called, optional arguments will be identified by the -``-`` prefix, and the remaining arguments will be assumed to be positional:: +When :meth:`~ArgumentParser.parse_args` is called, optional arguments will be +identified by the ``-`` prefix, and the remaining arguments will be assumed to +be positional:: >>> parser = argparse.ArgumentParser(prog='PROG') >>> parser.add_argument('-f', '--foo') @@ -639,8 +645,8 @@ :class:`ArgumentParser` objects associate command-line args with actions. These actions can do just about anything with the command-line args associated with them, though most actions simply add an attribute to the object returned by -:meth:`parse_args`. The ``action`` keyword argument specifies how the -command-line args should be handled. The supported actions are: +:meth:`~ArgumentParser.parse_args`. The ``action`` keyword argument specifies +how the command-line args should be handled. The supported actions are: * ``'store'`` - This just stores the argument's value. This is the default action. For example:: @@ -692,8 +698,8 @@ Namespace(types=[, ]) * ``'version'`` - This expects a ``version=`` keyword argument in the - :meth:`add_argument` call, and prints version information and exits when - invoked. + :meth:`~ArgumentParser.add_argument` call, and prints version information + and exits when invoked. >>> import argparse >>> parser = argparse.ArgumentParser(prog='PROG') @@ -709,11 +715,12 @@ * ``parser`` - The ArgumentParser object which contains this action. * ``namespace`` - The namespace object that will be returned by - :meth:`parse_args`. Most actions add an attribute to this object. + :meth:`~ArgumentParser.parse_args`. Most actions add an attribute to this + object. * ``values`` - The associated command-line args, with any type-conversions applied. (Type-conversions are specified with the type_ keyword argument to - :meth:`add_argument`. + :meth:`~ArgumentParser.add_argument`. * ``option_string`` - The option string that was used to invoke this action. The ``option_string`` argument is optional, and will be absent if the action @@ -820,21 +827,20 @@ const ^^^^^ -The ``const`` argument of :meth:`add_argument` is used to hold constant values -that are not read from the command line but are required for the various -ArgumentParser actions. The two most common uses of it are: +The ``const`` argument of :meth:`~ArgumentParser.add_argument` is used to hold +constant values that are not read from the command line but are required for +the various :class:`ArgumentParser` actions. The two most common uses of it are: -* When :meth:`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:`parse_args`. See the action_ - description for examples. +* 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. -* When :meth:`add_argument` is called with option strings (like ``-f`` or - ``--foo``) and ``nargs='?'``. This creates an optional argument that can be - followed by zero or one command-line args. When parsing the command line, if - the option string is encountered with no command-line arg following it, the - value of ``const`` will be assumed instead. See the nargs_ description for - examples. +* When :meth:`~ArgumentParser.add_argument` is called with option strings + (like ``-f`` or ``--foo``) and ``nargs='?'``. This creates an optional + argument that can be followed by zero or one command-line args. + When parsing the command line, if the option string is encountered with no + command-line arg following it, the value of ``const`` will be assumed instead. + See the nargs_ description for examples. The ``const`` keyword argument defaults to ``None``. @@ -843,10 +849,11 @@ ^^^^^^^ All optional arguments and some positional arguments may be omitted at the -command line. The ``default`` keyword argument of :meth:`add_argument`, whose -value defaults to ``None``, specifies what value should be used if the -command-line arg is not present. For optional arguments, the ``default`` value -is used when the option string was not present at the command line:: +command line. The ``default`` keyword argument of +:meth:`~ArgumentParser.add_argument`, whose value defaults to ``None``, +specifies what value should be used if the command-line arg is not present. +For optional arguments, the ``default`` value is used when the option string +was not present at the command line:: >>> parser = argparse.ArgumentParser() >>> parser.add_argument('--foo', default=42) @@ -883,9 +890,9 @@ By default, ArgumentParser objects read command-line args in as simple strings. However, quite often the command-line string should instead be interpreted as another type, like a :class:`float`, :class:`int` or :class:`file`. The -``type`` keyword argument of :meth:`add_argument` allows any necessary -type-checking and type-conversions to be performed. Many common built-in types -can be used directly as the value of the ``type`` argument:: +``type`` keyword argument of :meth:`~ArgumentParser.add_argument` allows any +necessary type-checking and type-conversions to be performed. Many common +built-in types can be used directly as the value of the ``type`` argument:: >>> parser = argparse.ArgumentParser() >>> parser.add_argument('foo', type=int) @@ -941,9 +948,9 @@ Some command-line args should be selected from a restricted set of values. These can be handled by passing a container object as the ``choices`` keyword -argument to :meth:`add_argument`. When the command line is parsed, arg values -will be checked, and an error message will be displayed if the arg was not one -of the acceptable values:: +argument to :meth:`~ArgumentParser.add_argument`. When the command line is +parsed, arg values will be checked, and an error message will be displayed if +the arg was not one of the acceptable values:: >>> parser = argparse.ArgumentParser(prog='PROG') >>> parser.add_argument('foo', choices='abc') @@ -976,7 +983,7 @@ In general, the :mod:`argparse` module assumes that flags like ``-f`` and ``--bar`` indicate *optional* arguments, which can always be omitted at the command line. To make an option *required*, ``True`` can be specified for the ``required=`` -keyword argument to :meth:`add_argument`:: +keyword argument to :meth:`~ArgumentParser.add_argument`:: >>> parser = argparse.ArgumentParser() >>> parser.add_argument('--foo', required=True) @@ -986,8 +993,9 @@ usage: argparse.py [-h] [--foo FOO] argparse.py: error: option --foo is required -As the example shows, if an option is marked as ``required``, :meth:`parse_args` -will report an error if that option is not present at the command line. +As the example shows, if an option is marked as ``required``, +:meth:`~ArgumentParser.parse_args` will report an error if that option is not +present at the command line. .. note:: @@ -1021,7 +1029,7 @@ The ``help`` strings can include various format specifiers to avoid repetition of things like the program name or the argument default_. The available specifiers include the program name, ``%(prog)s`` and most keyword arguments to -:meth:`add_argument`, e.g. ``%(default)s``, ``%(type)s``, etc.:: +:meth:`~ArgumentParser.add_argument`, e.g. ``%(default)s``, ``%(type)s``, etc.:: >>> parser = argparse.ArgumentParser(prog='frobble') >>> parser.add_argument('bar', nargs='?', type=int, default=42, @@ -1081,8 +1089,8 @@ --foo YYY Note that ``metavar`` only changes the *displayed* name - the name of the -attribute on the :meth:`parse_args` object is still determined by the dest_ -value. +attribute on the :meth:`~ArgumentParser.parse_args` object is still determined +by the dest_ value. Different values of ``nargs`` may cause the metavar to be used multiple times. Providing a tuple to ``metavar`` specifies a different display for each of the @@ -1104,10 +1112,11 @@ ^^^^ Most :class:`ArgumentParser` actions add some value as an attribute of the -object returned by :meth:`parse_args`. The name of this attribute is determined -by the ``dest`` keyword argument of :meth:`add_argument`. For positional -argument actions, ``dest`` is normally supplied as the first argument to -:meth:`add_argument`:: +object returned by :meth:`~ArgumentParser.parse_args`. The name of this +attribute is determined by the ``dest`` keyword argument of +:meth:`~ArgumentParser.add_argument`. For positional argument actions, +``dest`` is normally supplied as the first argument to +:meth:`~ArgumentParser.add_argument`:: >>> parser = argparse.ArgumentParser() >>> parser.add_argument('bar') @@ -1158,9 +1167,9 @@ Option value syntax ^^^^^^^^^^^^^^^^^^^ -The :meth:`parse_args` method supports several ways of specifying the value of -an option (if it takes one). In the simplest case, the option and its value are -passed as two separate arguments:: +The :meth:`~ArgumentParser.parse_args` method supports several ways of +specifying the value of an option (if it takes one). In the simplest case, the +option and its value are passed as two separate arguments:: >>> parser = argparse.ArgumentParser(prog='PROG') >>> parser.add_argument('-x') @@ -1197,10 +1206,10 @@ Invalid arguments ^^^^^^^^^^^^^^^^^ -While parsing the command line, ``parse_args`` checks for a variety of errors, -including ambiguous options, invalid types, invalid options, wrong number of -positional arguments, etc. When it encounters such an error, it exits and -prints the error along with a usage message:: +While parsing the command line, :meth:`~ArgumentParser.parse_args` checks for a +variety of errors, including ambiguous options, invalid types, invalid options, +wrong number of positional arguments, etc. When it encounters such an error, +it exits and prints the error along with a usage message:: >>> parser = argparse.ArgumentParser(prog='PROG') >>> parser.add_argument('--foo', type=int) @@ -1225,13 +1234,13 @@ Arguments containing ``"-"`` ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -The ``parse_args`` method attempts to give errors whenever the user has clearly -made a mistake, but some situations are inherently ambiguous. For example, the -command-line arg ``'-1'`` could either be an attempt to specify an option or an -attempt to provide a positional argument. The ``parse_args`` method is cautious -here: positional arguments may only begin with ``'-'`` if they look like -negative numbers and there are no options in the parser that look like negative -numbers:: +The :meth:`~ArgumentParser.parse_args` method attempts to give errors whenever +the user has clearly made a mistake, but some situations are inherently +ambiguous. For example, the command-line arg ``'-1'`` could either be an +attempt to specify an option or an attempt to provide a positional argument. +The :meth:`~ArgumentParser.parse_args` method is cautious here: positional +arguments may only begin with ``'-'`` if they look like negative numbers and +there are no options in the parser that look like negative numbers:: >>> parser = argparse.ArgumentParser(prog='PROG') >>> parser.add_argument('-x') @@ -1265,7 +1274,8 @@ If you have positional arguments that must begin with ``'-'`` and don't look like negative numbers, you can insert the pseudo-argument ``'--'`` which tells -``parse_args`` that everything after that is a positional argument:: +:meth:`~ArgumentParser.parse_args` that everything after that is a positional +argument:: >>> parser.parse_args(['--', '-f']) Namespace(foo='-f', one=None) @@ -1274,8 +1284,8 @@ Argument abbreviations ^^^^^^^^^^^^^^^^^^^^^^ -The :meth:`parse_args` method allows long options to be abbreviated if the -abbreviation is unambiguous:: +The :meth:`~ArgumentParser.parse_args` method allows long options to be +abbreviated if the abbreviation is unambiguous:: >>> parser = argparse.ArgumentParser(prog='PROG') >>> parser.add_argument('-bacon') @@ -1296,7 +1306,8 @@ Sometimes it may be useful to have an ArgumentParser parse args other than those of :data:`sys.argv`. This can be accomplished by passing a list of strings to -``parse_args``. This is useful for testing at the interactive prompt:: +:meth:`~ArgumentParser.parse_args`. This is useful for testing at the +interactive prompt:: >>> parser = argparse.ArgumentParser() >>> parser.add_argument( @@ -1314,11 +1325,11 @@ The Namespace object ^^^^^^^^^^^^^^^^^^^^ -By default, :meth:`parse_args` will return a new object of type :class:`Namespace` -where the necessary attributes have been set. This class is deliberately simple, -just an :class:`object` subclass with a readable string representation. If you -prefer to have dict-like view of the attributes, you can use the standard Python -idiom via :func:`vars`:: +By default, :meth:`~ArgumentParser.parse_args` will return a new object of type +:class:`Namespace` where the necessary attributes have been set. This class is +deliberately simple, just an :class:`object` subclass with a readable string +representation. If you prefer to have dict-like view of the attributes, you +can use the standard Python idiom via :func:`vars`:: >>> parser = argparse.ArgumentParser() >>> parser.add_argument('--foo') @@ -1357,9 +1368,9 @@ :class:`ArgumentParser` supports the creation of such sub-commands with the :meth:`add_subparsers` method. The :meth:`add_subparsers` method is normally called with no arguments and returns an special action object. This object - has a single method, ``add_parser``, which takes a command name and any - :class:`ArgumentParser` constructor arguments, and returns an - :class:`ArgumentParser` object that can be modified as usual. + has a single method, :meth:`~ArgumentParser.add_parser`, which takes a + command name and any :class:`ArgumentParser` constructor arguments, and + returns an :class:`ArgumentParser` object that can be modified as usual. Some example usage:: @@ -1393,7 +1404,7 @@ for that particular parser will be printed. The help message will not include parent parser or sibling parser messages. (A help message for each subparser command, however, can be given by supplying the ``help=`` argument - to ``add_parser`` as above.) + to :meth:`add_parser` as above.) :: @@ -1612,7 +1623,8 @@ PROG: error: one of the arguments --foo --bar is required Note that currently mutually exclusive argument groups do not support the - *title* and *description* arguments of :meth:`add_argument_group`. + *title* and *description* arguments of + :meth:`~ArgumentParser.add_argument_group`. Parser defaults @@ -1622,7 +1634,7 @@ Most of the time, the attributes of the object returned by :meth:`parse_args` will be fully determined by inspecting the command-line args and the argument - actions. :meth:`ArgumentParser.set_defaults` allows some additional + actions. :meth:`set_defaults` allows some additional attributes that are determined without any inspection of the command line to be added:: @@ -1659,9 +1671,9 @@ Printing help ^^^^^^^^^^^^^ -In most typical applications, :meth:`parse_args` will take care of formatting -and printing any usage or error messages. However, several formatting methods -are available: +In most typical applications, :meth:`~ArgumentParser.parse_args` will take +care of formatting and printing any usage or error messages. However, several +formatting methods are available: .. method:: ArgumentParser.print_usage(file=None) @@ -1696,7 +1708,7 @@ Sometimes a script may only parse a few of the command-line arguments, passing the remaining arguments on to another script or program. In these cases, the -:meth:`parse_known_args` method can be useful. It works much like +:meth:`~ArgumentParser.parse_known_args` method can be useful. It works much like :meth:`~ArgumentParser.parse_args` except that it does not produce an error when extra arguments are present. Instead, it returns a two item tuple containing the populated namespace and the list of remaining argument strings. @@ -1753,7 +1765,7 @@ Upgrading optparse code ----------------------- -Originally, the mod:`argparse` module had attempted to maintain compatibility +Originally, the :mod:`argparse` module had attempted to maintain compatibility with :mod:`optparse`. However, :mod:`optparse` was difficult to extend transparently, particularly with the changes required to support the new ``nargs=`` specifiers and better usage messages. When most everything in @@ -1762,8 +1774,8 @@ A partial upgrade path from :mod:`optparse` to :mod:`argparse`: -* Replace all ``add_option()`` calls with :meth:`ArgumentParser.add_argument` - calls. +* Replace all :meth:`optparse.OptionParser.add_option` calls with + :meth:`ArgumentParser.add_argument` calls. * Replace ``options, args = parser.parse_args()`` with ``args = parser.parse_args()`` and add additional :meth:`ArgumentParser.add_argument` -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 22 00:58:28 2011 From: python-checkins at python.org (ezio.melotti) Date: Fri, 22 Apr 2011 00:58:28 +0200 Subject: [Python-checkins] cpython (3.2): Fix some more markup glitches in argparse doc. Message-ID: http://hg.python.org/cpython/rev/9f1767d680ff changeset: 69526:9f1767d680ff branch: 3.2 parent: 69522:15f482996880 user: Ezio Melotti date: Fri Apr 22 01:42:10 2011 +0300 summary: Fix some more markup glitches in argparse doc. files: Doc/library/argparse.rst | 214 ++++++++++++++------------ 1 files changed, 113 insertions(+), 101 deletions(-) diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -97,7 +97,7 @@ ... const=sum, default=max, ... help='sum the integers (default: find the max)') -Later, calling :meth:`parse_args` will return an object with +Later, calling :meth:`~ArgumentParser.parse_args` will return an object with two attributes, ``integers`` and ``accumulate``. The ``integers`` attribute will be a list of one or more ints, and the ``accumulate`` attribute will be either the :func:`sum` function, if ``--sum`` was specified at the command line, @@ -295,10 +295,10 @@ Namespace(f='bar') Arguments read from a file must by default be one per line (but see also -:meth:`convert_arg_line_to_args`) and are treated as if they were in the same -place as the original file referencing argument on the command line. So in the -example above, the expression ``['-f', 'foo', '@args.txt']`` is considered -equivalent to the expression ``['-f', 'foo', '-f', 'bar']``. +:meth:`~ArgumentParser.convert_arg_line_to_args`) and are treated as if they +were in the same place as the original file referencing argument on the command +line. So in the example above, the expression ``['-f', 'foo', '@args.txt']`` +is considered equivalent to the expression ``['-f', 'foo', '-f', 'bar']``. The ``fromfile_prefix_chars=`` argument defaults to ``None``, meaning that arguments will never be treated as file references. @@ -308,11 +308,12 @@ ^^^^^^^^^^^^^^^^ Generally, argument defaults are specified either by passing a default to -:meth:`add_argument` or by calling the :meth:`set_defaults` methods with a -specific set of name-value pairs. Sometimes however, it may be useful to -specify a single parser-wide default for arguments. This can be accomplished by -passing the ``argument_default=`` keyword argument to :class:`ArgumentParser`. -For example, to globally suppress attribute creation on :meth:`parse_args` +:meth:`~ArgumentParser.add_argument` or by calling the +:meth:`~ArgumentParser.set_defaults` methods with a specific set of name-value +pairs. Sometimes however, it may be useful to specify a single parser-wide +default for arguments. This can be accomplished by passing the +``argument_default=`` keyword argument to :class:`ArgumentParser`. For example, +to globally suppress attribute creation on :meth:`~ArgumentParser.parse_args` calls, we supply ``argument_default=SUPPRESS``:: >>> parser = argparse.ArgumentParser(argument_default=argparse.SUPPRESS) @@ -362,11 +363,14 @@ :class:`ArgumentParser` objects allow the help formatting to be customized by specifying an alternate formatting class. Currently, there are three such -classes: :class:`argparse.RawDescriptionHelpFormatter`, -:class:`argparse.RawTextHelpFormatter` and -:class:`argparse.ArgumentDefaultsHelpFormatter`. The first two allow more -control over how textual descriptions are displayed, while the last -automatically adds information about argument default values. +classes: + +.. class:: RawDescriptionHelpFormatter + RawTextHelpFormatter + ArgumentDefaultsHelpFormatter + +The first two allow more control over how textual descriptions are displayed, +while the last automatically adds information about argument default values. By default, :class:`ArgumentParser` objects line-wrap the description_ and epilog_ texts in command-line help messages:: @@ -391,7 +395,7 @@ likewise for this epilog whose whitespace will be cleaned up and whose words will be wrapped across a couple lines -Passing :class:`argparse.RawDescriptionHelpFormatter` as ``formatter_class=`` +Passing :class:`~argparse.RawDescriptionHelpFormatter` as ``formatter_class=`` indicates that description_ and epilog_ are already correctly formatted and should not be line-wrapped:: @@ -614,11 +618,12 @@ name or flags ^^^^^^^^^^^^^ -The :meth:`add_argument` method must know whether an optional argument, like -``-f`` or ``--foo``, or a positional argument, like a list of filenames, is -expected. The first arguments passed to :meth:`add_argument` must therefore be -either a series of flags, or a simple argument name. For example, an optional -argument could be created like:: +The :meth:`~ArgumentParser.add_argument` method must know whether an optional +argument, like ``-f`` or ``--foo``, or a positional argument, like a list of +filenames, is expected. The first arguments passed to +:meth:`~ArgumentParser.add_argument` must therefore be either a series of +flags, or a simple argument name. For example, an optional argument could +be created like:: >>> parser.add_argument('-f', '--foo') @@ -626,8 +631,9 @@ >>> parser.add_argument('bar') -When :meth:`parse_args` is called, optional arguments will be identified by the -``-`` prefix, and the remaining arguments will be assumed to be positional:: +When :meth:`~ArgumentParser.parse_args` is called, optional arguments will be +identified by the ``-`` prefix, and the remaining arguments will be assumed to +be positional:: >>> parser = argparse.ArgumentParser(prog='PROG') >>> parser.add_argument('-f', '--foo') @@ -647,8 +653,8 @@ :class:`ArgumentParser` objects associate command-line args with actions. These actions can do just about anything with the command-line args associated with them, though most actions simply add an attribute to the object returned by -:meth:`parse_args`. The ``action`` keyword argument specifies how the -command-line args should be handled. The supported actions are: +:meth:`~ArgumentParser.parse_args`. The ``action`` keyword argument specifies +how the command-line args should be handled. The supported actions are: * ``'store'`` - This just stores the argument's value. This is the default action. For example:: @@ -700,8 +706,8 @@ Namespace(types=[, ]) * ``'version'`` - This expects a ``version=`` keyword argument in the - :meth:`add_argument` call, and prints version information and exits when - invoked. + :meth:`~ArgumentParser.add_argument` call, and prints version information + and exits when invoked. >>> import argparse >>> parser = argparse.ArgumentParser(prog='PROG') @@ -717,11 +723,12 @@ * ``parser`` - The ArgumentParser object which contains this action. * ``namespace`` - The namespace object that will be returned by - :meth:`parse_args`. Most actions add an attribute to this object. + :meth:`~ArgumentParser.parse_args`. Most actions add an attribute to this + object. * ``values`` - The associated command-line args, with any type-conversions applied. (Type-conversions are specified with the type_ keyword argument to - :meth:`add_argument`. + :meth:`~ArgumentParser.add_argument`. * ``option_string`` - The option string that was used to invoke this action. The ``option_string`` argument is optional, and will be absent if the action @@ -828,21 +835,20 @@ const ^^^^^ -The ``const`` argument of :meth:`add_argument` is used to hold constant values -that are not read from the command line but are required for the various -ArgumentParser actions. The two most common uses of it are: +The ``const`` argument of :meth:`~ArgumentParser.add_argument` is used to hold +constant values that are not read from the command line but are required for +the various :class:`ArgumentParser` actions. The two most common uses of it are: -* When :meth:`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:`parse_args`. See the action_ - description for examples. +* 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. -* When :meth:`add_argument` is called with option strings (like ``-f`` or - ``--foo``) and ``nargs='?'``. This creates an optional argument that can be - followed by zero or one command-line args. When parsing the command line, if - the option string is encountered with no command-line arg following it, the - value of ``const`` will be assumed instead. See the nargs_ description for - examples. +* When :meth:`~ArgumentParser.add_argument` is called with option strings + (like ``-f`` or ``--foo``) and ``nargs='?'``. This creates an optional + argument that can be followed by zero or one command-line args. + When parsing the command line, if the option string is encountered with no + command-line arg following it, the value of ``const`` will be assumed instead. + See the nargs_ description for examples. The ``const`` keyword argument defaults to ``None``. @@ -851,10 +857,11 @@ ^^^^^^^ All optional arguments and some positional arguments may be omitted at the -command line. The ``default`` keyword argument of :meth:`add_argument`, whose -value defaults to ``None``, specifies what value should be used if the -command-line arg is not present. For optional arguments, the ``default`` value -is used when the option string was not present at the command line:: +command line. The ``default`` keyword argument of +:meth:`~ArgumentParser.add_argument`, whose value defaults to ``None``, +specifies what value should be used if the command-line arg is not present. +For optional arguments, the ``default`` value is used when the option string +was not present at the command line:: >>> parser = argparse.ArgumentParser() >>> parser.add_argument('--foo', default=42) @@ -888,12 +895,12 @@ type ^^^^ -By default, ArgumentParser objects read command-line args in as simple strings. -However, quite often the command-line string should instead be interpreted as -another type, like a :class:`float` or :class:`int`. The ``type`` keyword -argument of :meth:`add_argument` allows any necessary type-checking and -type-conversions to be performed. Common built-in types and functions can be -used directly as the value of the ``type`` argument:: +By default, :class:`ArgumentParser` objects read command-line args in as simple +strings. However, quite often the command-line string should instead be +interpreted as another type, like a :class:`float` or :class:`int`. The +``type`` keyword argument of :meth:`~ArgumentParser.add_argument` allows any +necessary type-checking and type-conversions to be performed. Common built-in +types and functions can be used directly as the value of the ``type`` argument:: >>> parser = argparse.ArgumentParser() >>> parser.add_argument('foo', type=int) @@ -949,9 +956,9 @@ Some command-line args should be selected from a restricted set of values. These can be handled by passing a container object as the ``choices`` keyword -argument to :meth:`add_argument`. When the command line is parsed, arg values -will be checked, and an error message will be displayed if the arg was not one -of the acceptable values:: +argument to :meth:`~ArgumentParser.add_argument`. When the command line is +parsed, arg values will be checked, and an error message will be displayed if +the arg was not one of the acceptable values:: >>> parser = argparse.ArgumentParser(prog='PROG') >>> parser.add_argument('foo', choices='abc') @@ -984,7 +991,7 @@ In general, the :mod:`argparse` module assumes that flags like ``-f`` and ``--bar`` indicate *optional* arguments, which can always be omitted at the command line. To make an option *required*, ``True`` can be specified for the ``required=`` -keyword argument to :meth:`add_argument`:: +keyword argument to :meth:`~ArgumentParser.add_argument`:: >>> parser = argparse.ArgumentParser() >>> parser.add_argument('--foo', required=True) @@ -994,8 +1001,9 @@ usage: argparse.py [-h] [--foo FOO] argparse.py: error: option --foo is required -As the example shows, if an option is marked as ``required``, :meth:`parse_args` -will report an error if that option is not present at the command line. +As the example shows, if an option is marked as ``required``, +:meth:`~ArgumentParser.parse_args` will report an error if that option is not +present at the command line. .. note:: @@ -1029,7 +1037,7 @@ The ``help`` strings can include various format specifiers to avoid repetition of things like the program name or the argument default_. The available specifiers include the program name, ``%(prog)s`` and most keyword arguments to -:meth:`add_argument`, e.g. ``%(default)s``, ``%(type)s``, etc.:: +:meth:`~ArgumentParser.add_argument`, e.g. ``%(default)s``, ``%(type)s``, etc.:: >>> parser = argparse.ArgumentParser(prog='frobble') >>> parser.add_argument('bar', nargs='?', type=int, default=42, @@ -1089,8 +1097,8 @@ --foo YYY Note that ``metavar`` only changes the *displayed* name - the name of the -attribute on the :meth:`parse_args` object is still determined by the dest_ -value. +attribute on the :meth:`~ArgumentParser.parse_args` object is still determined +by the dest_ value. Different values of ``nargs`` may cause the metavar to be used multiple times. Providing a tuple to ``metavar`` specifies a different display for each of the @@ -1112,10 +1120,11 @@ ^^^^ Most :class:`ArgumentParser` actions add some value as an attribute of the -object returned by :meth:`parse_args`. The name of this attribute is determined -by the ``dest`` keyword argument of :meth:`add_argument`. For positional -argument actions, ``dest`` is normally supplied as the first argument to -:meth:`add_argument`:: +object returned by :meth:`~ArgumentParser.parse_args`. The name of this +attribute is determined by the ``dest`` keyword argument of +:meth:`~ArgumentParser.add_argument`. For positional argument actions, +``dest`` is normally supplied as the first argument to +:meth:`~ArgumentParser.add_argument`:: >>> parser = argparse.ArgumentParser() >>> parser.add_argument('bar') @@ -1166,9 +1175,9 @@ Option value syntax ^^^^^^^^^^^^^^^^^^^ -The :meth:`parse_args` method supports several ways of specifying the value of -an option (if it takes one). In the simplest case, the option and its value are -passed as two separate arguments:: +The :meth:`~ArgumentParser.parse_args` method supports several ways of +specifying the value of an option (if it takes one). In the simplest case, the +option and its value are passed as two separate arguments:: >>> parser = argparse.ArgumentParser(prog='PROG') >>> parser.add_argument('-x') @@ -1205,10 +1214,10 @@ Invalid arguments ^^^^^^^^^^^^^^^^^ -While parsing the command line, ``parse_args`` checks for a variety of errors, -including ambiguous options, invalid types, invalid options, wrong number of -positional arguments, etc. When it encounters such an error, it exits and -prints the error along with a usage message:: +While parsing the command line, :meth:`~ArgumentParser.parse_args` checks for a +variety of errors, including ambiguous options, invalid types, invalid options, +wrong number of positional arguments, etc. When it encounters such an error, +it exits and prints the error along with a usage message:: >>> parser = argparse.ArgumentParser(prog='PROG') >>> parser.add_argument('--foo', type=int) @@ -1233,13 +1242,13 @@ Arguments containing ``"-"`` ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -The ``parse_args`` method attempts to give errors whenever the user has clearly -made a mistake, but some situations are inherently ambiguous. For example, the -command-line arg ``'-1'`` could either be an attempt to specify an option or an -attempt to provide a positional argument. The ``parse_args`` method is cautious -here: positional arguments may only begin with ``'-'`` if they look like -negative numbers and there are no options in the parser that look like negative -numbers:: +The :meth:`~ArgumentParser.parse_args` method attempts to give errors whenever +the user has clearly made a mistake, but some situations are inherently +ambiguous. For example, the command-line arg ``'-1'`` could either be an +attempt to specify an option or an attempt to provide a positional argument. +The :meth:`~ArgumentParser.parse_args` method is cautious here: positional +arguments may only begin with ``'-'`` if they look like negative numbers and +there are no options in the parser that look like negative numbers:: >>> parser = argparse.ArgumentParser(prog='PROG') >>> parser.add_argument('-x') @@ -1273,7 +1282,8 @@ If you have positional arguments that must begin with ``'-'`` and don't look like negative numbers, you can insert the pseudo-argument ``'--'`` which tells -``parse_args`` that everything after that is a positional argument:: +:meth:`~ArgumentParser.parse_args` that everything after that is a positional +argument:: >>> parser.parse_args(['--', '-f']) Namespace(foo='-f', one=None) @@ -1282,8 +1292,8 @@ Argument abbreviations ^^^^^^^^^^^^^^^^^^^^^^ -The :meth:`parse_args` method allows long options to be abbreviated if the -abbreviation is unambiguous:: +The :meth:`~ArgumentParser.parse_args` method allows long options to be +abbreviated if the abbreviation is unambiguous:: >>> parser = argparse.ArgumentParser(prog='PROG') >>> parser.add_argument('-bacon') @@ -1304,7 +1314,8 @@ Sometimes it may be useful to have an ArgumentParser parse args other than those of :data:`sys.argv`. This can be accomplished by passing a list of strings to -``parse_args``. This is useful for testing at the interactive prompt:: +:meth:`~ArgumentParser.parse_args`. This is useful for testing at the +interactive prompt:: >>> parser = argparse.ArgumentParser() >>> parser.add_argument( @@ -1322,11 +1333,11 @@ The Namespace object ^^^^^^^^^^^^^^^^^^^^ -By default, :meth:`parse_args` will return a new object of type :class:`Namespace` -where the necessary attributes have been set. This class is deliberately simple, -just an :class:`object` subclass with a readable string representation. If you -prefer to have dict-like view of the attributes, you can use the standard Python -idiom via :func:`vars`:: +By default, :meth:`~ArgumentParser.parse_args` will return a new object of type +:class:`Namespace` where the necessary attributes have been set. This class is +deliberately simple, just an :class:`object` subclass with a readable string +representation. If you prefer to have dict-like view of the attributes, you +can use the standard Python idiom via :func:`vars`:: >>> parser = argparse.ArgumentParser() >>> parser.add_argument('--foo') @@ -1365,9 +1376,9 @@ :class:`ArgumentParser` supports the creation of such sub-commands with the :meth:`add_subparsers` method. The :meth:`add_subparsers` method is normally called with no arguments and returns an special action object. This object - has a single method, ``add_parser``, which takes a command name and any - :class:`ArgumentParser` constructor arguments, and returns an - :class:`ArgumentParser` object that can be modified as usual. + has a single method, :meth:`~ArgumentParser.add_parser`, which takes a + command name and any :class:`ArgumentParser` constructor arguments, and + returns an :class:`ArgumentParser` object that can be modified as usual. Some example usage:: @@ -1401,7 +1412,7 @@ for that particular parser will be printed. The help message will not include parent parser or sibling parser messages. (A help message for each subparser command, however, can be given by supplying the ``help=`` argument - to ``add_parser`` as above.) + to :meth:`add_parser` as above.) :: @@ -1630,7 +1641,8 @@ PROG: error: one of the arguments --foo --bar is required Note that currently mutually exclusive argument groups do not support the - *title* and *description* arguments of :meth:`add_argument_group`. + *title* and *description* arguments of + :meth:`~ArgumentParser.add_argument_group`. Parser defaults @@ -1640,7 +1652,7 @@ Most of the time, the attributes of the object returned by :meth:`parse_args` will be fully determined by inspecting the command-line args and the argument - actions. :meth:`ArgumentParser.set_defaults` allows some additional + actions. :meth:`set_defaults` allows some additional attributes that are determined without any inspection of the command line to be added:: @@ -1677,9 +1689,9 @@ Printing help ^^^^^^^^^^^^^ -In most typical applications, :meth:`parse_args` will take care of formatting -and printing any usage or error messages. However, several formatting methods -are available: +In most typical applications, :meth:`~ArgumentParser.parse_args` will take +care of formatting and printing any usage or error messages. However, several +formatting methods are available: .. method:: ArgumentParser.print_usage(file=None) @@ -1714,7 +1726,7 @@ Sometimes a script may only parse a few of the command-line arguments, passing the remaining arguments on to another script or program. In these cases, the -:meth:`parse_known_args` method can be useful. It works much like +:meth:`~ArgumentParser.parse_known_args` method can be useful. It works much like :meth:`~ArgumentParser.parse_args` except that it does not produce an error when extra arguments are present. Instead, it returns a two item tuple containing the populated namespace and the list of remaining argument strings. @@ -1770,7 +1782,7 @@ Upgrading optparse code ----------------------- -Originally, the mod:`argparse` module had attempted to maintain compatibility +Originally, the :mod:`argparse` module had attempted to maintain compatibility with :mod:`optparse`. However, :mod:`optparse` was difficult to extend transparently, particularly with the changes required to support the new ``nargs=`` specifiers and better usage messages. When most everything in @@ -1779,8 +1791,8 @@ A partial upgrade path from :mod:`optparse` to :mod:`argparse`: -* Replace all ``add_option()`` calls with :meth:`ArgumentParser.add_argument` - calls. +* Replace all :meth:`optparse.OptionParser.add_option` calls with + :meth:`ArgumentParser.add_argument` calls. * Replace ``options, args = parser.parse_args()`` with ``args = parser.parse_args()`` and add additional :meth:`ArgumentParser.add_argument` -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 22 00:58:29 2011 From: python-checkins at python.org (ezio.melotti) Date: Fri, 22 Apr 2011 00:58:29 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge with 3.2. Message-ID: http://hg.python.org/cpython/rev/3fd70900a9a7 changeset: 69527:3fd70900a9a7 parent: 69523:8568762381b4 parent: 69526:9f1767d680ff user: Ezio Melotti date: Fri Apr 22 01:57:47 2011 +0300 summary: Merge with 3.2. files: Doc/library/argparse.rst | 207 ++++++++++++++------------ 1 files changed, 111 insertions(+), 96 deletions(-) diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -97,7 +97,7 @@ ... const=sum, default=max, ... help='sum the integers (default: find the max)') -Later, calling :meth:`parse_args` will return an object with +Later, calling :meth:`~ArgumentParser.parse_args` will return an object with two attributes, ``integers`` and ``accumulate``. The ``integers`` attribute will be a list of one or more ints, and the ``accumulate`` attribute will be either the :func:`sum` function, if ``--sum`` was specified at the command line, @@ -295,10 +295,10 @@ Namespace(f='bar') Arguments read from a file must by default be one per line (but see also -:meth:`convert_arg_line_to_args`) and are treated as if they were in the same -place as the original file referencing argument on the command line. So in the -example above, the expression ``['-f', 'foo', '@args.txt']`` is considered -equivalent to the expression ``['-f', 'foo', '-f', 'bar']``. +:meth:`~ArgumentParser.convert_arg_line_to_args`) and are treated as if they +were in the same place as the original file referencing argument on the command +line. So in the example above, the expression ``['-f', 'foo', '@args.txt']`` +is considered equivalent to the expression ``['-f', 'foo', '-f', 'bar']``. The ``fromfile_prefix_chars=`` argument defaults to ``None``, meaning that arguments will never be treated as file references. @@ -308,11 +308,12 @@ ^^^^^^^^^^^^^^^^ Generally, argument defaults are specified either by passing a default to -:meth:`add_argument` or by calling the :meth:`set_defaults` methods with a -specific set of name-value pairs. Sometimes however, it may be useful to -specify a single parser-wide default for arguments. This can be accomplished by -passing the ``argument_default=`` keyword argument to :class:`ArgumentParser`. -For example, to globally suppress attribute creation on :meth:`parse_args` +:meth:`~ArgumentParser.add_argument` or by calling the +:meth:`~ArgumentParser.set_defaults` methods with a specific set of name-value +pairs. Sometimes however, it may be useful to specify a single parser-wide +default for arguments. This can be accomplished by passing the +``argument_default=`` keyword argument to :class:`ArgumentParser`. For example, +to globally suppress attribute creation on :meth:`~ArgumentParser.parse_args` calls, we supply ``argument_default=SUPPRESS``:: >>> parser = argparse.ArgumentParser(argument_default=argparse.SUPPRESS) @@ -361,7 +362,13 @@ ^^^^^^^^^^^^^^^ :class:`ArgumentParser` objects allow the help formatting to be customized by -specifying an alternate formatting class. +specifying an alternate formatting class. Currently, there are four such +classes: + +.. class:: RawDescriptionHelpFormatter + RawTextHelpFormatter + ArgumentDefaultsHelpFormatter + MetavarTypeHelpFormatter :class:`RawDescriptionHelpFormatter` and :class:`RawTextHelpFormatter` give more control over how textual descriptions are displayed. @@ -630,11 +637,12 @@ name or flags ^^^^^^^^^^^^^ -The :meth:`add_argument` method must know whether an optional argument, like -``-f`` or ``--foo``, or a positional argument, like a list of filenames, is -expected. The first arguments passed to :meth:`add_argument` must therefore be -either a series of flags, or a simple argument name. For example, an optional -argument could be created like:: +The :meth:`~ArgumentParser.add_argument` method must know whether an optional +argument, like ``-f`` or ``--foo``, or a positional argument, like a list of +filenames, is expected. The first arguments passed to +:meth:`~ArgumentParser.add_argument` must therefore be either a series of +flags, or a simple argument name. For example, an optional argument could +be created like:: >>> parser.add_argument('-f', '--foo') @@ -642,8 +650,9 @@ >>> parser.add_argument('bar') -When :meth:`parse_args` is called, optional arguments will be identified by the -``-`` prefix, and the remaining arguments will be assumed to be positional:: +When :meth:`~ArgumentParser.parse_args` is called, optional arguments will be +identified by the ``-`` prefix, and the remaining arguments will be assumed to +be positional:: >>> parser = argparse.ArgumentParser(prog='PROG') >>> parser.add_argument('-f', '--foo') @@ -663,8 +672,8 @@ :class:`ArgumentParser` objects associate command-line args with actions. These actions can do just about anything with the command-line args associated with them, though most actions simply add an attribute to the object returned by -:meth:`parse_args`. The ``action`` keyword argument specifies how the -command-line args should be handled. The supported actions are: +:meth:`~ArgumentParser.parse_args`. The ``action`` keyword argument specifies +how the command-line args should be handled. The supported actions are: * ``'store'`` - This just stores the argument's value. This is the default action. For example:: @@ -716,8 +725,8 @@ Namespace(types=[, ]) * ``'version'`` - This expects a ``version=`` keyword argument in the - :meth:`add_argument` call, and prints version information and exits when - invoked. + :meth:`~ArgumentParser.add_argument` call, and prints version information + and exits when invoked. >>> import argparse >>> parser = argparse.ArgumentParser(prog='PROG') @@ -733,11 +742,12 @@ * ``parser`` - The ArgumentParser object which contains this action. * ``namespace`` - The namespace object that will be returned by - :meth:`parse_args`. Most actions add an attribute to this object. + :meth:`~ArgumentParser.parse_args`. Most actions add an attribute to this + object. * ``values`` - The associated command-line args, with any type-conversions applied. (Type-conversions are specified with the type_ keyword argument to - :meth:`add_argument`. + :meth:`~ArgumentParser.add_argument`. * ``option_string`` - The option string that was used to invoke this action. The ``option_string`` argument is optional, and will be absent if the action @@ -844,21 +854,20 @@ const ^^^^^ -The ``const`` argument of :meth:`add_argument` is used to hold constant values -that are not read from the command line but are required for the various -ArgumentParser actions. The two most common uses of it are: +The ``const`` argument of :meth:`~ArgumentParser.add_argument` is used to hold +constant values that are not read from the command line but are required for +the various :class:`ArgumentParser` actions. The two most common uses of it are: -* When :meth:`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:`parse_args`. See the action_ - description for examples. +* 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. -* When :meth:`add_argument` is called with option strings (like ``-f`` or - ``--foo``) and ``nargs='?'``. This creates an optional argument that can be - followed by zero or one command-line args. When parsing the command line, if - the option string is encountered with no command-line arg following it, the - value of ``const`` will be assumed instead. See the nargs_ description for - examples. +* When :meth:`~ArgumentParser.add_argument` is called with option strings + (like ``-f`` or ``--foo``) and ``nargs='?'``. This creates an optional + argument that can be followed by zero or one command-line args. + When parsing the command line, if the option string is encountered with no + command-line arg following it, the value of ``const`` will be assumed instead. + See the nargs_ description for examples. The ``const`` keyword argument defaults to ``None``. @@ -867,10 +876,11 @@ ^^^^^^^ All optional arguments and some positional arguments may be omitted at the -command line. The ``default`` keyword argument of :meth:`add_argument`, whose -value defaults to ``None``, specifies what value should be used if the -command-line arg is not present. For optional arguments, the ``default`` value -is used when the option string was not present at the command line:: +command line. The ``default`` keyword argument of +:meth:`~ArgumentParser.add_argument`, whose value defaults to ``None``, +specifies what value should be used if the command-line arg is not present. +For optional arguments, the ``default`` value is used when the option string +was not present at the command line:: >>> parser = argparse.ArgumentParser() >>> parser.add_argument('--foo', default=42) @@ -904,12 +914,12 @@ type ^^^^ -By default, ArgumentParser objects read command-line args in as simple strings. -However, quite often the command-line string should instead be interpreted as -another type, like a :class:`float` or :class:`int`. The ``type`` keyword -argument of :meth:`add_argument` allows any necessary type-checking and -type-conversions to be performed. Common built-in types and functions can be -used directly as the value of the ``type`` argument:: +By default, :class:`ArgumentParser` objects read command-line args in as simple +strings. However, quite often the command-line string should instead be +interpreted as another type, like a :class:`float` or :class:`int`. The +``type`` keyword argument of :meth:`~ArgumentParser.add_argument` allows any +necessary type-checking and type-conversions to be performed. Common built-in +types and functions can be used directly as the value of the ``type`` argument:: >>> parser = argparse.ArgumentParser() >>> parser.add_argument('foo', type=int) @@ -965,9 +975,9 @@ Some command-line args should be selected from a restricted set of values. These can be handled by passing a container object as the ``choices`` keyword -argument to :meth:`add_argument`. When the command line is parsed, arg values -will be checked, and an error message will be displayed if the arg was not one -of the acceptable values:: +argument to :meth:`~ArgumentParser.add_argument`. When the command line is +parsed, arg values will be checked, and an error message will be displayed if +the arg was not one of the acceptable values:: >>> parser = argparse.ArgumentParser(prog='PROG') >>> parser.add_argument('foo', choices='abc') @@ -1000,7 +1010,7 @@ In general, the :mod:`argparse` module assumes that flags like ``-f`` and ``--bar`` indicate *optional* arguments, which can always be omitted at the command line. To make an option *required*, ``True`` can be specified for the ``required=`` -keyword argument to :meth:`add_argument`:: +keyword argument to :meth:`~ArgumentParser.add_argument`:: >>> parser = argparse.ArgumentParser() >>> parser.add_argument('--foo', required=True) @@ -1010,8 +1020,9 @@ usage: argparse.py [-h] [--foo FOO] argparse.py: error: option --foo is required -As the example shows, if an option is marked as ``required``, :meth:`parse_args` -will report an error if that option is not present at the command line. +As the example shows, if an option is marked as ``required``, +:meth:`~ArgumentParser.parse_args` will report an error if that option is not +present at the command line. .. note:: @@ -1045,7 +1056,7 @@ The ``help`` strings can include various format specifiers to avoid repetition of things like the program name or the argument default_. The available specifiers include the program name, ``%(prog)s`` and most keyword arguments to -:meth:`add_argument`, e.g. ``%(default)s``, ``%(type)s``, etc.:: +:meth:`~ArgumentParser.add_argument`, e.g. ``%(default)s``, ``%(type)s``, etc.:: >>> parser = argparse.ArgumentParser(prog='frobble') >>> parser.add_argument('bar', nargs='?', type=int, default=42, @@ -1105,8 +1116,8 @@ --foo YYY Note that ``metavar`` only changes the *displayed* name - the name of the -attribute on the :meth:`parse_args` object is still determined by the dest_ -value. +attribute on the :meth:`~ArgumentParser.parse_args` object is still determined +by the dest_ value. Different values of ``nargs`` may cause the metavar to be used multiple times. Providing a tuple to ``metavar`` specifies a different display for each of the @@ -1128,10 +1139,11 @@ ^^^^ Most :class:`ArgumentParser` actions add some value as an attribute of the -object returned by :meth:`parse_args`. The name of this attribute is determined -by the ``dest`` keyword argument of :meth:`add_argument`. For positional -argument actions, ``dest`` is normally supplied as the first argument to -:meth:`add_argument`:: +object returned by :meth:`~ArgumentParser.parse_args`. The name of this +attribute is determined by the ``dest`` keyword argument of +:meth:`~ArgumentParser.add_argument`. For positional argument actions, +``dest`` is normally supplied as the first argument to +:meth:`~ArgumentParser.add_argument`:: >>> parser = argparse.ArgumentParser() >>> parser.add_argument('bar') @@ -1182,9 +1194,9 @@ Option value syntax ^^^^^^^^^^^^^^^^^^^ -The :meth:`parse_args` method supports several ways of specifying the value of -an option (if it takes one). In the simplest case, the option and its value are -passed as two separate arguments:: +The :meth:`~ArgumentParser.parse_args` method supports several ways of +specifying the value of an option (if it takes one). In the simplest case, the +option and its value are passed as two separate arguments:: >>> parser = argparse.ArgumentParser(prog='PROG') >>> parser.add_argument('-x') @@ -1221,10 +1233,10 @@ Invalid arguments ^^^^^^^^^^^^^^^^^ -While parsing the command line, ``parse_args`` checks for a variety of errors, -including ambiguous options, invalid types, invalid options, wrong number of -positional arguments, etc. When it encounters such an error, it exits and -prints the error along with a usage message:: +While parsing the command line, :meth:`~ArgumentParser.parse_args` checks for a +variety of errors, including ambiguous options, invalid types, invalid options, +wrong number of positional arguments, etc. When it encounters such an error, +it exits and prints the error along with a usage message:: >>> parser = argparse.ArgumentParser(prog='PROG') >>> parser.add_argument('--foo', type=int) @@ -1249,13 +1261,13 @@ Arguments containing ``"-"`` ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -The ``parse_args`` method attempts to give errors whenever the user has clearly -made a mistake, but some situations are inherently ambiguous. For example, the -command-line arg ``'-1'`` could either be an attempt to specify an option or an -attempt to provide a positional argument. The ``parse_args`` method is cautious -here: positional arguments may only begin with ``'-'`` if they look like -negative numbers and there are no options in the parser that look like negative -numbers:: +The :meth:`~ArgumentParser.parse_args` method attempts to give errors whenever +the user has clearly made a mistake, but some situations are inherently +ambiguous. For example, the command-line arg ``'-1'`` could either be an +attempt to specify an option or an attempt to provide a positional argument. +The :meth:`~ArgumentParser.parse_args` method is cautious here: positional +arguments may only begin with ``'-'`` if they look like negative numbers and +there are no options in the parser that look like negative numbers:: >>> parser = argparse.ArgumentParser(prog='PROG') >>> parser.add_argument('-x') @@ -1289,7 +1301,8 @@ If you have positional arguments that must begin with ``'-'`` and don't look like negative numbers, you can insert the pseudo-argument ``'--'`` which tells -``parse_args`` that everything after that is a positional argument:: +:meth:`~ArgumentParser.parse_args` that everything after that is a positional +argument:: >>> parser.parse_args(['--', '-f']) Namespace(foo='-f', one=None) @@ -1298,8 +1311,8 @@ Argument abbreviations ^^^^^^^^^^^^^^^^^^^^^^ -The :meth:`parse_args` method allows long options to be abbreviated if the -abbreviation is unambiguous:: +The :meth:`~ArgumentParser.parse_args` method allows long options to be +abbreviated if the abbreviation is unambiguous:: >>> parser = argparse.ArgumentParser(prog='PROG') >>> parser.add_argument('-bacon') @@ -1320,7 +1333,8 @@ Sometimes it may be useful to have an ArgumentParser parse args other than those of :data:`sys.argv`. This can be accomplished by passing a list of strings to -``parse_args``. This is useful for testing at the interactive prompt:: +:meth:`~ArgumentParser.parse_args`. This is useful for testing at the +interactive prompt:: >>> parser = argparse.ArgumentParser() >>> parser.add_argument( @@ -1338,11 +1352,11 @@ The Namespace object ^^^^^^^^^^^^^^^^^^^^ -By default, :meth:`parse_args` will return a new object of type :class:`Namespace` -where the necessary attributes have been set. This class is deliberately simple, -just an :class:`object` subclass with a readable string representation. If you -prefer to have dict-like view of the attributes, you can use the standard Python -idiom via :func:`vars`:: +By default, :meth:`~ArgumentParser.parse_args` will return a new object of type +:class:`Namespace` where the necessary attributes have been set. This class is +deliberately simple, just an :class:`object` subclass with a readable string +representation. If you prefer to have dict-like view of the attributes, you +can use the standard Python idiom via :func:`vars`:: >>> parser = argparse.ArgumentParser() >>> parser.add_argument('--foo') @@ -1381,9 +1395,9 @@ :class:`ArgumentParser` supports the creation of such sub-commands with the :meth:`add_subparsers` method. The :meth:`add_subparsers` method is normally called with no arguments and returns an special action object. This object - has a single method, ``add_parser``, which takes a command name and any - :class:`ArgumentParser` constructor arguments, and returns an - :class:`ArgumentParser` object that can be modified as usual. + has a single method, :meth:`~ArgumentParser.add_parser`, which takes a + command name and any :class:`ArgumentParser` constructor arguments, and + returns an :class:`ArgumentParser` object that can be modified as usual. Some example usage:: @@ -1417,7 +1431,7 @@ for that particular parser will be printed. The help message will not include parent parser or sibling parser messages. (A help message for each subparser command, however, can be given by supplying the ``help=`` argument - to ``add_parser`` as above.) + to :meth:`add_parser` as above.) :: @@ -1646,7 +1660,8 @@ PROG: error: one of the arguments --foo --bar is required Note that currently mutually exclusive argument groups do not support the - *title* and *description* arguments of :meth:`add_argument_group`. + *title* and *description* arguments of + :meth:`~ArgumentParser.add_argument_group`. Parser defaults @@ -1656,7 +1671,7 @@ Most of the time, the attributes of the object returned by :meth:`parse_args` will be fully determined by inspecting the command-line args and the argument - actions. :meth:`ArgumentParser.set_defaults` allows some additional + actions. :meth:`set_defaults` allows some additional attributes that are determined without any inspection of the command line to be added:: @@ -1693,9 +1708,9 @@ Printing help ^^^^^^^^^^^^^ -In most typical applications, :meth:`parse_args` will take care of formatting -and printing any usage or error messages. However, several formatting methods -are available: +In most typical applications, :meth:`~ArgumentParser.parse_args` will take +care of formatting and printing any usage or error messages. However, several +formatting methods are available: .. method:: ArgumentParser.print_usage(file=None) @@ -1730,7 +1745,7 @@ Sometimes a script may only parse a few of the command-line arguments, passing the remaining arguments on to another script or program. In these cases, the -:meth:`parse_known_args` method can be useful. It works much like +:meth:`~ArgumentParser.parse_known_args` method can be useful. It works much like :meth:`~ArgumentParser.parse_args` except that it does not produce an error when extra arguments are present. Instead, it returns a two item tuple containing the populated namespace and the list of remaining argument strings. @@ -1786,7 +1801,7 @@ Upgrading optparse code ----------------------- -Originally, the mod:`argparse` module had attempted to maintain compatibility +Originally, the :mod:`argparse` module had attempted to maintain compatibility with :mod:`optparse`. However, :mod:`optparse` was difficult to extend transparently, particularly with the changes required to support the new ``nargs=`` specifiers and better usage messages. When most everything in @@ -1795,8 +1810,8 @@ A partial upgrade path from :mod:`optparse` to :mod:`argparse`: -* Replace all ``add_option()`` calls with :meth:`ArgumentParser.add_argument` - calls. +* Replace all :meth:`optparse.OptionParser.add_option` calls with + :meth:`ArgumentParser.add_argument` calls. * Replace ``options, args = parser.parse_args()`` with ``args = parser.parse_args()`` and add additional :meth:`ArgumentParser.add_argument` -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 22 01:17:51 2011 From: python-checkins at python.org (vinay.sajip) Date: Fri, 22 Apr 2011 01:17:51 +0200 Subject: [Python-checkins] cpython: Fixed bug in test_logging. Message-ID: http://hg.python.org/cpython/rev/fecf9e6d7630 changeset: 69528:fecf9e6d7630 user: Vinay Sajip date: Fri Apr 22 00:17:46 2011 +0100 summary: Fixed bug in test_logging. files: Lib/test/test_logging.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) 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 @@ -2356,7 +2356,7 @@ def _test_log(self, method, level=None): called = [] patch(self, logging, 'basicConfig', - lambda *a, **kw: called.append(a, kw)) + lambda *a, **kw: called.append((a, kw))) recording = RecordingHandler() logging.root.addHandler(recording) -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Fri Apr 22 04:57:38 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Fri, 22 Apr 2011 04:57:38 +0200 Subject: [Python-checkins] Daily reference leaks (fecf9e6d7630): sum=0 Message-ID: results for fecf9e6d7630 on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflog1pgkoq', '-x'] From python-checkins at python.org Sat Apr 23 00:42:26 2011 From: python-checkins at python.org (victor.stinner) Date: Sat, 23 Apr 2011 00:42:26 +0200 Subject: [Python-checkins] cpython (3.2): Issue #9319: Fix a crash on parsing a Python source code without encoding Message-ID: http://hg.python.org/cpython/rev/fa5e348889c2 changeset: 69529:fa5e348889c2 branch: 3.2 parent: 69526:9f1767d680ff user: Victor Stinner date: Sat Apr 23 00:41:19 2011 +0200 summary: Issue #9319: Fix a crash on parsing a Python source code without encoding cookie and not valid in UTF-8: use "" as the filename instead of reading from NULL. files: Lib/test/test_imp.py | 3 +++ Parser/tokenizer.c | 5 ++++- 2 files changed, 7 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_imp.py b/Lib/test/test_imp.py --- a/Lib/test/test_imp.py +++ b/Lib/test/test_imp.py @@ -170,6 +170,9 @@ support.unlink(init_file_name + ext) support.rmtree(test_package_name) + def test_issue9319(self): + imp.find_module("test/badsyntax_pep3120") + class ReloadTests(unittest.TestCase): diff --git a/Parser/tokenizer.c b/Parser/tokenizer.c --- a/Parser/tokenizer.c +++ b/Parser/tokenizer.c @@ -586,7 +586,10 @@ if (badchar) { /* Need to add 1 to the line number, since this line has not been counted, yet. */ - filename = PyUnicode_DecodeFSDefault(tok->filename); + if (tok->filename != NULL) + filename = PyUnicode_DecodeFSDefault(tok->filename); + else + filename = PyUnicode_FromString(""); if (filename != NULL) { PyErr_Format(PyExc_SyntaxError, "Non-UTF-8 code starting with '\\x%.2x' " -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 23 01:27:44 2011 From: python-checkins at python.org (victor.stinner) Date: Sat, 23 Apr 2011 01:27:44 +0200 Subject: [Python-checkins] cpython (3.2): Issue #9319: Fix the unit test Message-ID: http://hg.python.org/cpython/rev/701069f9888c changeset: 69530:701069f9888c branch: 3.2 user: Victor Stinner date: Sat Apr 23 01:24:11 2011 +0200 summary: Issue #9319: Fix the unit test files: Lib/test/test_imp.py | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_imp.py b/Lib/test/test_imp.py --- a/Lib/test/test_imp.py +++ b/Lib/test/test_imp.py @@ -171,7 +171,8 @@ support.rmtree(test_package_name) def test_issue9319(self): - imp.find_module("test/badsyntax_pep3120") + self.assertRaises(SyntaxError, + imp.find_module, "test/badsyntax_pep3120") class ReloadTests(unittest.TestCase): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 23 03:51:48 2011 From: python-checkins at python.org (raymond.hettinger) Date: Sat, 23 Apr 2011 03:51:48 +0200 Subject: [Python-checkins] cpython (2.7): Cleanups to remove dependencies and add docstrings. Message-ID: http://hg.python.org/cpython/rev/fa277cbd66bb changeset: 69531:fa277cbd66bb branch: 2.7 parent: 69525:c821d3d335e8 user: Raymond Hettinger date: Fri Apr 22 18:49:53 2011 -0700 summary: Cleanups to remove dependencies and add docstrings. files: Lib/collections.py | 87 +++++++++++++++++++-------------- 1 files changed, 49 insertions(+), 38 deletions(-) diff --git a/Lib/collections.py b/Lib/collections.py --- a/Lib/collections.py +++ b/Lib/collections.py @@ -13,30 +13,9 @@ from itertools import repeat as _repeat, chain as _chain, starmap as _starmap, \ ifilter as _ifilter, imap as _imap try: - from thread import get_ident + from thread import get_ident as _get_ident except ImportError: - from dummy_thread import get_ident - -def _recursive_repr(user_function): - 'Decorator to make a repr function return "..." for a recursive call' - repr_running = set() - - def wrapper(self): - key = id(self), get_ident() - if key in repr_running: - return '...' - repr_running.add(key) - try: - result = user_function(self) - finally: - repr_running.discard(key) - return result - - # Can't use functools.wraps() here because of bootstrap issues - wrapper.__module__ = getattr(user_function, '__module__') - wrapper.__doc__ = getattr(user_function, '__doc__') - wrapper.__name__ = getattr(user_function, '__name__') - return wrapper + from dummy_thread import get_ident as _get_ident ################################################################################ @@ -123,14 +102,37 @@ pass dict.clear(self) - update = __update = MutableMapping.update - keys = MutableMapping.keys - values = MutableMapping.values - items = MutableMapping.items - iterkeys = MutableMapping.iterkeys - itervalues = MutableMapping.itervalues - iteritems = MutableMapping.iteritems - __ne__ = MutableMapping.__ne__ + # -- the following methods do not depend on the internal structure -- + + def keys(self): + 'od.keys() -> list of keys in od' + return list(self) + + def values(self): + 'od.values() -> list of values in od' + return [self[key] for key in self] + + def items(self): + 'od.items() -> list of (key, value) pairs in od' + return [(key, self[key]) for key in self] + + def iterkeys(self): + 'od.iterkeys() -> an iterator over the keys in od' + return iter(self) + + def itervalues(self): + 'od.itervalues -> an iterator over the values in od' + for k in self: + yield self[k] + + def iteritems(self): + 'od.iteritems -> an iterator over the (key, value) items in od' + for k in self: + yield (k, self[k]) + + update = MutableMapping.update + + __update = update # let subclasses override update without breaking __init__ def viewkeys(self): "od.viewkeys() -> a set-like object providing a view on od's keys" @@ -173,12 +175,18 @@ value = self.pop(key) return key, value - @_recursive_repr - def __repr__(self): + def __repr__(self, _repr_running={}): 'od.__repr__() <==> repr(od)' - if not self: - return '%s()' % (self.__class__.__name__,) - return '%s(%r)' % (self.__class__.__name__, self.items()) + call_key = id(self), _get_ident() + if call_key in _repr_running: + return '...' + _repr_running[call_key] = 1 + try: + if not self: + return '%s()' % (self.__class__.__name__,) + return '%s(%r)' % (self.__class__.__name__, self.items()) + finally: + del _repr_running[call_key] def __reduce__(self): 'Return state information for pickling' @@ -211,10 +219,13 @@ ''' if isinstance(other, OrderedDict): - return len(self)==len(other) and \ - all(_imap(_eq, self.iteritems(), other.iteritems())) + return len(self)==len(other) and self.items() == other.items() return dict.__eq__(self, other) + def __ne__(self, other): + 'od.__ne__(y) <==> od!=y' + return not self == other + ################################################################################ ### namedtuple -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Sat Apr 23 05:01:48 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sat, 23 Apr 2011 05:01:48 +0200 Subject: [Python-checkins] Daily reference leaks (fecf9e6d7630): sum=0 Message-ID: results for fecf9e6d7630 on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflognzB8vY', '-x'] From python-checkins at python.org Sat Apr 23 17:21:42 2011 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 23 Apr 2011 17:21:42 +0200 Subject: [Python-checkins] cpython: Issue #11382: Trivial system calls, such as dup() or pipe(), needn't Message-ID: http://hg.python.org/cpython/rev/eb7297fd5840 changeset: 69532:eb7297fd5840 parent: 69528:fecf9e6d7630 user: Antoine Pitrou date: Sat Apr 23 17:21:13 2011 +0200 summary: Issue #11382: Trivial system calls, such as dup() or pipe(), needn't release the GIL. Patch by Charles-Fran?ois Natali. files: Misc/NEWS | 3 +++ Modules/posixmodule.c | 14 -------------- 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -113,6 +113,9 @@ Library ------- +- Issue #11382: Trivial system calls, such as dup() or pipe(), needn't + release the GIL. Patch by Charles-Fran?ois Natali. + - Issue #11223: Add threading._info() function providing informations about the thread implementation. diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -3083,9 +3083,7 @@ if (!PyArg_ParseTuple(args, "ii", &which, &who)) return NULL; errno = 0; - Py_BEGIN_ALLOW_THREADS retval = getpriority(which, who); - Py_END_ALLOW_THREADS if (errno != 0) return posix_error(); return PyLong_FromLong((long)retval); @@ -3105,9 +3103,7 @@ if (!PyArg_ParseTuple(args, "iii", &which, &who, &prio)) return NULL; - Py_BEGIN_ALLOW_THREADS retval = setpriority(which, who, prio); - Py_END_ALLOW_THREADS if (retval == -1) return posix_error(); Py_RETURN_NONE; @@ -6010,9 +6006,7 @@ return NULL; if (!_PyVerify_fd(fd)) return posix_error(); - Py_BEGIN_ALLOW_THREADS fd = dup(fd); - Py_END_ALLOW_THREADS if (fd < 0) return posix_error(); return PyLong_FromLong((long)fd); @@ -6031,9 +6025,7 @@ return NULL; if (!_PyVerify_fd_dup2(fd, fd2)) return posix_error(); - Py_BEGIN_ALLOW_THREADS res = dup2(fd, fd2); - Py_END_ALLOW_THREADS if (res < 0) return posix_error(); Py_INCREF(Py_None); @@ -6525,9 +6517,7 @@ HFILE read, write; APIRET rc; - Py_BEGIN_ALLOW_THREADS rc = DosCreatePipe( &read, &write, 4096); - Py_END_ALLOW_THREADS if (rc != NO_ERROR) return os2_error(rc); @@ -6536,9 +6526,7 @@ #if !defined(MS_WINDOWS) int fds[2]; int res; - Py_BEGIN_ALLOW_THREADS res = pipe(fds); - Py_END_ALLOW_THREADS if (res != 0) return posix_error(); return Py_BuildValue("(ii)", fds[0], fds[1]); @@ -6546,9 +6534,7 @@ HANDLE read, write; int read_fd, write_fd; BOOL ok; - Py_BEGIN_ALLOW_THREADS ok = CreatePipe(&read, &write, NULL, 0); - Py_END_ALLOW_THREADS if (!ok) return win32_error("CreatePipe", NULL); read_fd = _open_osfhandle((Py_intptr_t)read, 0); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 23 17:56:24 2011 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 23 Apr 2011 17:56:24 +0200 Subject: [Python-checkins] cpython: Issue #11258: Speed up ctypes.util.find_library() under Linux by a factor Message-ID: http://hg.python.org/cpython/rev/19d9f0a177de changeset: 69533:19d9f0a177de user: Antoine Pitrou date: Sat Apr 23 17:51:04 2011 +0200 summary: Issue #11258: Speed up ctypes.util.find_library() under Linux by a factor of 5 to 10. Initial patch by Jonas H. files: Lib/ctypes/util.py | 22 ++++++++++++++-------- Misc/ACKS | 1 + Misc/NEWS | 3 +++ 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/Lib/ctypes/util.py b/Lib/ctypes/util.py --- a/Lib/ctypes/util.py +++ b/Lib/ctypes/util.py @@ -1,5 +1,6 @@ import sys, os import contextlib +import subprocess # find_library(name) returns the pathname of a library, or None. if os.name == "nt": @@ -203,14 +204,19 @@ abi_type = mach_map.get(machine, 'libc6') # XXX assuming GLIBC's ldconfig (with option -p) - expr = r'(\S+)\s+\((%s(?:, OS ABI:[^\)]*)?)\)[^/]*(/[^\(\)\s]*lib%s\.[^\(\)\s]*)' \ - % (abi_type, re.escape(name)) - with contextlib.closing(os.popen('LC_ALL=C LANG=C /sbin/ldconfig -p 2>/dev/null')) as f: - data = f.read() - res = re.search(expr, data) - if not res: - return None - return res.group(1) + regex = os.fsencode( + '\s+(lib%s\.[^\s]+)\s+\(%s' % (re.escape(name), abi_type)) + try: + with subprocess.Popen(['/sbin/ldconfig', '-p'], + stdin=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + stdout=subprocess.PIPE, + env={'LC_ALL': 'C', 'LANG': 'C'}) as p: + res = re.search(regex, p.stdout.read()) + if res: + return os.fsdecode(res.group(1)) + except OSError: + pass def find_library(name): return _findSoname_ldconfig(name) or _get_soname(_findLib_gcc(name)) diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -338,6 +338,7 @@ Michael Guravage Lars Gust?bel Thomas G?ttler +Jonas H. Barry Haddow Paul ten Hagen Rasmus Hahn diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -113,6 +113,9 @@ Library ------- +- Issue #11258: Speed up ctypes.util.find_library() under Linux by a factor + of 5 to 10. Initial patch by Jonas H. + - Issue #11382: Trivial system calls, such as dup() or pipe(), needn't release the GIL. Patch by Charles-Fran?ois Natali. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 23 17:56:25 2011 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 23 Apr 2011 17:56:25 +0200 Subject: [Python-checkins] cpython: Remove unused private function Message-ID: http://hg.python.org/cpython/rev/020ebe0be33e changeset: 69534:020ebe0be33e user: Antoine Pitrou date: Sat Apr 23 17:56:06 2011 +0200 summary: Remove unused private function files: Lib/ctypes/util.py | 16 ---------------- 1 files changed, 0 insertions(+), 16 deletions(-) diff --git a/Lib/ctypes/util.py b/Lib/ctypes/util.py --- a/Lib/ctypes/util.py +++ b/Lib/ctypes/util.py @@ -172,22 +172,6 @@ else: - def _findLib_ldconfig(name): - # XXX assuming GLIBC's ldconfig (with option -p) - expr = r'/[^\(\)\s]*lib%s\.[^\(\)\s]*' % re.escape(name) - with contextlib.closing(os.popen('/sbin/ldconfig -p 2>/dev/null')) as f: - data = f.read() - res = re.search(expr, data) - if not res: - # Hm, this works only for libs needed by the python executable. - cmd = 'ldd %s 2>/dev/null' % sys.executable - with contextlib.closing(os.popen(cmd)) as f: - data = f.read() - res = re.search(expr, data) - if not res: - return None - return res.group(0) - def _findSoname_ldconfig(name): import struct if struct.calcsize('l') == 4: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Apr 24 01:27:41 2011 From: python-checkins at python.org (raymond.hettinger) Date: Sun, 24 Apr 2011 01:27:41 +0200 Subject: [Python-checkins] cpython (2.7): Minor code simplification. Message-ID: http://hg.python.org/cpython/rev/a3d5149bdd70 changeset: 69535:a3d5149bdd70 branch: 2.7 parent: 69531:fa277cbd66bb user: Raymond Hettinger date: Sat Apr 23 15:41:38 2011 -0700 summary: Minor code simplification. files: Lib/collections.py | 6 ++---- 1 files changed, 2 insertions(+), 4 deletions(-) diff --git a/Lib/collections.py b/Lib/collections.py --- a/Lib/collections.py +++ b/Lib/collections.py @@ -45,10 +45,8 @@ try: self.__root except AttributeError: - self.__root = root = [None, None, None] # sentinel node - PREV = 0 - NEXT = 1 - root[PREV] = root[NEXT] = root + self.__root = root = [] # sentinel node + root[:] = [root, root, None] self.__map = {} self.__update(*args, **kwds) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Apr 24 01:27:46 2011 From: python-checkins at python.org (raymond.hettinger) Date: Sun, 24 Apr 2011 01:27:46 +0200 Subject: [Python-checkins] cpython (2.7): Minor code simplification. Message-ID: http://hg.python.org/cpython/rev/d6729016eedc changeset: 69536:d6729016eedc branch: 2.7 user: Raymond Hettinger date: Sat Apr 23 15:51:38 2011 -0700 summary: Minor code simplification. files: Lib/collections.py | 30 +++++++++++++++--------------- 1 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Lib/collections.py b/Lib/collections.py --- a/Lib/collections.py +++ b/Lib/collections.py @@ -65,9 +65,7 @@ # Deleting an existing item uses self.__map to find the link which is # then removed by updating the links in the predecessor and successor nodes. dict_delitem(self, key) - link = self.__map.pop(key) - link_prev = link[PREV] - link_next = link[NEXT] + link_prev, link_next, key = self.__map.pop(key) link_prev[NEXT] = link_next link_next[PREV] = link_prev @@ -132,18 +130,6 @@ __update = update # let subclasses override update without breaking __init__ - def viewkeys(self): - "od.viewkeys() -> a set-like object providing a view on od's keys" - return KeysView(self) - - def viewvalues(self): - "od.viewvalues() -> an object providing a view on od's values" - return ValuesView(self) - - def viewitems(self): - "od.viewitems() -> a set-like object providing a view on od's items" - return ItemsView(self) - __marker = object() def pop(self, key, default=__marker): @@ -224,6 +210,20 @@ 'od.__ne__(y) <==> od!=y' return not self == other + # -- the following methods support python 3.x style dictionary views -- + + def viewkeys(self): + "od.viewkeys() -> a set-like object providing a view on od's keys" + return KeysView(self) + + def viewvalues(self): + "od.viewvalues() -> an object providing a view on od's values" + return ValuesView(self) + + def viewitems(self): + "od.viewitems() -> a set-like object providing a view on od's items" + return ItemsView(self) + ################################################################################ ### namedtuple -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Apr 24 03:37:45 2011 From: python-checkins at python.org (raymond.hettinger) Date: Sun, 24 Apr 2011 03:37:45 +0200 Subject: [Python-checkins] cpython (2.7): Remove unused imports Message-ID: http://hg.python.org/cpython/rev/ad89231ee568 changeset: 69537:ad89231ee568 branch: 2.7 user: Raymond Hettinger date: Sat Apr 23 18:37:37 2011 -0700 summary: Remove unused imports files: Lib/collections.py | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Lib/collections.py b/Lib/collections.py --- a/Lib/collections.py +++ b/Lib/collections.py @@ -6,12 +6,12 @@ __all__ += _abcoll.__all__ from _collections import deque, defaultdict -from operator import itemgetter as _itemgetter, eq as _eq +from operator import itemgetter as _itemgetter from keyword import iskeyword as _iskeyword import sys as _sys import heapq as _heapq -from itertools import repeat as _repeat, chain as _chain, starmap as _starmap, \ - ifilter as _ifilter, imap as _imap +from itertools import repeat as _repeat, chain as _chain, starmap as _starmap + try: from thread import get_ident as _get_ident except ImportError: -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Sun Apr 24 04:57:37 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sun, 24 Apr 2011 04:57:37 +0200 Subject: [Python-checkins] Daily reference leaks (020ebe0be33e): sum=-323 Message-ID: results for 020ebe0be33e on branch "default" -------------------------------------------- test_pyexpat leaked [-56, -267, 0] references, sum=-323 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogh7KcyS', '-x'] From python-checkins at python.org Sun Apr 24 05:12:56 2011 From: python-checkins at python.org (raymond.hettinger) Date: Sun, 24 Apr 2011 05:12:56 +0200 Subject: [Python-checkins] cpython (2.7): Minor code clean-up. Message-ID: http://hg.python.org/cpython/rev/34129a7366b6 changeset: 69538:34129a7366b6 branch: 2.7 user: Raymond Hettinger date: Sat Apr 23 20:11:50 2011 -0700 summary: Minor code clean-up. files: Lib/collections.py | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Lib/collections.py b/Lib/collections.py --- a/Lib/collections.py +++ b/Lib/collections.py @@ -92,7 +92,8 @@ try: for node in self.__map.itervalues(): del node[:] - self.__root[:] = [self.__root, self.__root, None] + root = self.__root + root[:] = [root, root, None] self.__map.clear() except AttributeError: pass -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Apr 24 21:30:49 2011 From: python-checkins at python.org (raymond.hettinger) Date: Sun, 24 Apr 2011 21:30:49 +0200 Subject: [Python-checkins] cpython (2.7): Remove unused branch in the clear() method. Minor comment edits. Message-ID: http://hg.python.org/cpython/rev/45f26582250b changeset: 69539:45f26582250b branch: 2.7 user: Raymond Hettinger date: Sun Apr 24 12:30:39 2011 -0700 summary: Remove unused branch in the clear() method. Minor comment edits. files: Lib/collections.py | 33 +++++++++++++++------------------ 1 files changed, 15 insertions(+), 18 deletions(-) diff --git a/Lib/collections.py b/Lib/collections.py --- a/Lib/collections.py +++ b/Lib/collections.py @@ -27,9 +27,9 @@ # An inherited dict maps keys to values. # The inherited dict provides __getitem__, __len__, __contains__, and get. # The remaining methods are order-aware. - # Big-O running times for all methods are the same as for regular dictionaries. + # Big-O running times for all methods are the same as regular dictionaries. - # The internal self.__map dictionary maps keys to links in a doubly linked list. + # The internal self.__map dict maps keys to links in a doubly linked list. # The circular doubly linked list starts and ends with a sentinel element. # The sentinel element never gets deleted (this simplifies the algorithm). # Each link is stored as a list of length three: [PREV, NEXT, KEY]. @@ -52,8 +52,8 @@ def __setitem__(self, key, value, PREV=0, NEXT=1, dict_setitem=dict.__setitem__): 'od.__setitem__(i, y) <==> od[i]=y' - # Setting a new item creates a new link which goes at the end of the linked - # list, and the inherited dictionary is updated with the new key/value pair. + # Setting a new item creates a new link at the end of the linked list, + # and the inherited dictionary is updated with the new key/value pair. if key not in self: root = self.__root last = root[PREV] @@ -62,8 +62,8 @@ def __delitem__(self, key, PREV=0, NEXT=1, dict_delitem=dict.__delitem__): 'od.__delitem__(y) <==> del od[y]' - # Deleting an existing item uses self.__map to find the link which is - # then removed by updating the links in the predecessor and successor nodes. + # Deleting an existing item uses self.__map to find the link which gets + # removed by updating the links in the predecessor and successor nodes. dict_delitem(self, key) link_prev, link_next, key = self.__map.pop(key) link_prev[NEXT] = link_next @@ -89,14 +89,11 @@ def clear(self): 'od.clear() -> None. Remove all items from od.' - try: - for node in self.__map.itervalues(): - del node[:] - root = self.__root - root[:] = [root, root, None] - self.__map.clear() - except AttributeError: - pass + for node in self.__map.itervalues(): + del node[:] + root = self.__root + root[:] = [root, root, None] + self.__map.clear() dict.clear(self) # -- the following methods do not depend on the internal structure -- @@ -129,7 +126,7 @@ update = MutableMapping.update - __update = update # let subclasses override update without breaking __init__ + __update = update # let subclasses override update without breaking __init__ __marker = object() @@ -193,10 +190,10 @@ and values equal to v (which defaults to None). ''' - d = cls() + self = cls() for key in iterable: - d[key] = value - return d + self[key] = value + return self def __eq__(self, other): '''od.__eq__(y) <==> od==y. Comparison to another OD is order-sensitive -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Apr 24 21:55:41 2011 From: python-checkins at python.org (raymond.hettinger) Date: Sun, 24 Apr 2011 21:55:41 +0200 Subject: [Python-checkins] cpython (2.7): Other minor clean-ups. Message-ID: http://hg.python.org/cpython/rev/c64c41974d1f changeset: 69540:c64c41974d1f branch: 2.7 user: Raymond Hettinger date: Sun Apr 24 12:55:28 2011 -0700 summary: Other minor clean-ups. files: Lib/collections.py | 23 +++++++++++++++-------- 1 files changed, 15 insertions(+), 8 deletions(-) diff --git a/Lib/collections.py b/Lib/collections.py --- a/Lib/collections.py +++ b/Lib/collections.py @@ -35,9 +35,9 @@ # Each link is stored as a list of length three: [PREV, NEXT, KEY]. def __init__(self, *args, **kwds): - '''Initialize an ordered dictionary. Signature is the same as for - regular dictionaries, but keyword arguments are not recommended - because their insertion order is arbitrary. + '''Initialize an ordered dictionary. The signature is the same as + regular dictionaries, but keyword arguments are not recommended because + their insertion order is arbitrary. ''' if len(args) > 1: @@ -69,18 +69,20 @@ link_prev[NEXT] = link_next link_next[PREV] = link_prev - def __iter__(self, NEXT=1, KEY=2): + def __iter__(self): 'od.__iter__() <==> iter(od)' # Traverse the linked list in order. + NEXT, KEY = 1, 2 root = self.__root curr = root[NEXT] while curr is not root: yield curr[KEY] curr = curr[NEXT] - def __reversed__(self, PREV=0, KEY=2): + def __reversed__(self): 'od.__reversed__() <==> reversed(od)' # Traverse the linked list in reverse order. + PREV, KEY = 0, 2 root = self.__root curr = root[PREV] while curr is not root: @@ -120,7 +122,7 @@ yield self[k] def iteritems(self): - 'od.iteritems -> an iterator over the (key, value) items in od' + 'od.iteritems -> an iterator over the (key, value) pairs in od' for k in self: yield (k, self[k]) @@ -131,6 +133,11 @@ __marker = object() def pop(self, key, default=__marker): + '''od.pop(k[,d]) -> v, remove specified key and return the corresponding + value. If key is not found, d is returned if given, otherwise KeyError + is raised. + + ''' if key in self: result = self[key] del self[key] @@ -186,8 +193,8 @@ @classmethod def fromkeys(cls, iterable, value=None): - '''OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S - and values equal to v (which defaults to None). + '''OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S. + If not specified, the value defaults to None. ''' self = cls() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Apr 24 23:40:22 2011 From: python-checkins at python.org (raymond.hettinger) Date: Sun, 24 Apr 2011 23:40:22 +0200 Subject: [Python-checkins] cpython (3.2): Minor clean-ups to docstrings, comments, and var names. Message-ID: http://hg.python.org/cpython/rev/b0385ec55e7e changeset: 69541:b0385ec55e7e branch: 3.2 parent: 69530:701069f9888c user: Raymond Hettinger date: Sun Apr 24 14:26:08 2011 -0700 summary: Minor clean-ups to docstrings, comments, and var names. files: Lib/collections.py | 37 +++++++++++++++++++-------------- 1 files changed, 21 insertions(+), 16 deletions(-) diff --git a/Lib/collections.py b/Lib/collections.py --- a/Lib/collections.py +++ b/Lib/collections.py @@ -27,20 +27,20 @@ # An inherited dict maps keys to values. # The inherited dict provides __getitem__, __len__, __contains__, and get. # The remaining methods are order-aware. - # Big-O running times for all methods are the same as for regular dictionaries. + # Big-O running times for all methods are the same as regular dictionaries. - # The internal self.__map dictionary maps keys to links in a doubly linked list. + # The internal self.__map dict maps keys to links in a doubly linked list. # 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 stored in self.__hardroot with a weakref proxy in self.__root. + # The sentinel is in self.__hardroot with a weakref proxy in self.__root. # The prev/next 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. def __init__(self, *args, **kwds): - '''Initialize an ordered dictionary. Signature is the same as for - regular dictionaries, but keyword arguments are not recommended - because their insertion order is arbitrary. + '''Initialize an ordered dictionary. The signature is the same as + regular dictionaries, but keyword arguments are not recommended because + their insertion order is arbitrary. ''' if len(args) > 1: @@ -57,8 +57,8 @@ def __setitem__(self, key, value, dict_setitem=dict.__setitem__, proxy=_proxy, Link=_Link): 'od.__setitem__(i, y) <==> od[i]=y' - # Setting a new item creates a new link which goes at the end of the linked - # list, and the inherited dictionary is updated with the new key/value pair. + # Setting a new item creates a new link at the end of the linked list, + # and the inherited dictionary is updated with the new key/value pair. if key not in self: self.__map[key] = link = Link() root = self.__root @@ -70,8 +70,8 @@ def __delitem__(self, key, dict_delitem=dict.__delitem__): 'od.__delitem__(y) <==> del od[y]' - # Deleting an existing item uses self.__map to find the link which is - # then removed by updating the links in the predecessor and successor nodes. + # Deleting an existing item uses self.__map to find the link which gets + # removed by updating the links in the predecessor and successor nodes. dict_delitem(self, key) link = self.__map.pop(key) link_prev = link.prev @@ -169,6 +169,11 @@ __marker = object() def pop(self, key, default=__marker): + '''od.pop(k[,d]) -> v, remove specified key and return the corresponding + value. If key is not found, d is returned if given, otherwise KeyError + is raised. + + ''' if key in self: result = self[key] del self[key] @@ -178,7 +183,7 @@ return default def setdefault(self, key, default=None): - 'OD.setdefault(k[,d]) -> OD.get(k,d), also set OD[k]=d if k not in OD' + 'od.setdefault(k[,d]) -> od.get(k,d), also set od[k]=d if k not in od' if key in self: return self[key] self[key] = default @@ -207,14 +212,14 @@ @classmethod def fromkeys(cls, iterable, value=None): - '''OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S - and values equal to v (which defaults to None). + '''OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S. + If not specified, the value defaults to None. ''' - d = cls() + self = cls() for key in iterable: - d[key] = value - return d + self[key] = value + return self def __eq__(self, other): '''od.__eq__(y) <==> od==y. Comparison to another OD is order-sensitive -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Apr 24 23:40:25 2011 From: python-checkins at python.org (raymond.hettinger) Date: Sun, 24 Apr 2011 23:40:25 +0200 Subject: [Python-checkins] cpython: Minor clean-ups to docstrings, comments, and var names. Message-ID: http://hg.python.org/cpython/rev/3af980c9d7a0 changeset: 69542:3af980c9d7a0 parent: 69534:020ebe0be33e user: Raymond Hettinger date: Sun Apr 24 14:34:26 2011 -0700 summary: Minor clean-ups to docstrings, comments, and var names. files: Lib/collections/__init__.py | 37 ++++++++++++++---------- 1 files changed, 21 insertions(+), 16 deletions(-) diff --git a/Lib/collections/__init__.py b/Lib/collections/__init__.py --- a/Lib/collections/__init__.py +++ b/Lib/collections/__init__.py @@ -28,20 +28,20 @@ # An inherited dict maps keys to values. # The inherited dict provides __getitem__, __len__, __contains__, and get. # The remaining methods are order-aware. - # Big-O running times for all methods are the same as for regular dictionaries. + # Big-O running times for all methods are the same as regular dictionaries. - # The internal self.__map dictionary maps keys to links in a doubly linked list. + # The internal self.__map dict maps keys to links in a doubly linked list. # 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 stored in self.__hardroot with a weakref proxy in self.__root. + # The sentinel is in self.__hardroot with a weakref proxy in self.__root. # The prev/next 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. def __init__(self, *args, **kwds): - '''Initialize an ordered dictionary. Signature is the same as for - regular dictionaries, but keyword arguments are not recommended - because their insertion order is arbitrary. + '''Initialize an ordered dictionary. The signature is the same as + regular dictionaries, but keyword arguments are not recommended because + their insertion order is arbitrary. ''' if len(args) > 1: @@ -58,8 +58,8 @@ def __setitem__(self, key, value, dict_setitem=dict.__setitem__, proxy=_proxy, Link=_Link): 'od.__setitem__(i, y) <==> od[i]=y' - # Setting a new item creates a new link which goes at the end of the linked - # list, and the inherited dictionary is updated with the new key/value pair. + # Setting a new item creates a new link at the end of the linked list, + # and the inherited dictionary is updated with the new key/value pair. if key not in self: self.__map[key] = link = Link() root = self.__root @@ -71,8 +71,8 @@ def __delitem__(self, key, dict_delitem=dict.__delitem__): 'od.__delitem__(y) <==> del od[y]' - # Deleting an existing item uses self.__map to find the link which is - # then removed by updating the links in the predecessor and successor nodes. + # Deleting an existing item uses self.__map to find the link which gets + # removed by updating the links in the predecessor and successor nodes. dict_delitem(self, key) link = self.__map.pop(key) link_prev = link.prev @@ -170,6 +170,11 @@ __marker = object() def pop(self, key, default=__marker): + '''od.pop(k[,d]) -> v, remove specified key and return the corresponding + value. If key is not found, d is returned if given, otherwise KeyError + is raised. + + ''' if key in self: result = self[key] del self[key] @@ -179,7 +184,7 @@ return default def setdefault(self, key, default=None): - 'OD.setdefault(k[,d]) -> OD.get(k,d), also set OD[k]=d if k not in OD' + 'od.setdefault(k[,d]) -> od.get(k,d), also set od[k]=d if k not in od' if key in self: return self[key] self[key] = default @@ -208,14 +213,14 @@ @classmethod def fromkeys(cls, iterable, value=None): - '''OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S - and values equal to v (which defaults to None). + '''OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S. + If not specified, the value defaults to None. ''' - d = cls() + self = cls() for key in iterable: - d[key] = value - return d + self[key] = value + return self def __eq__(self, other): '''od.__eq__(y) <==> od==y. Comparison to another OD is order-sensitive -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Apr 24 23:42:25 2011 From: python-checkins at python.org (victor.stinner) Date: Sun, 24 Apr 2011 23:42:25 +0200 Subject: [Python-checkins] cpython: Issue #11915: threading.RLock()._release_save() raises a RuntimeError if the Message-ID: http://hg.python.org/cpython/rev/2c0da1c4f063 changeset: 69543:2c0da1c4f063 user: Victor Stinner date: Sun Apr 24 23:41:33 2011 +0200 summary: Issue #11915: threading.RLock()._release_save() raises a RuntimeError if the lock was not acquired. files: Lib/test/lock_tests.py | 2 ++ Lib/threading.py | 2 ++ Misc/NEWS | 3 +++ Modules/_threadmodule.c | 6 ++++++ 4 files changed, 13 insertions(+), 0 deletions(-) diff --git a/Lib/test/lock_tests.py b/Lib/test/lock_tests.py --- a/Lib/test/lock_tests.py +++ b/Lib/test/lock_tests.py @@ -247,6 +247,7 @@ # Cannot release an unacquired lock lock = self.locktype() self.assertRaises(RuntimeError, lock.release) + self.assertRaises(RuntimeError, lock._release_save) lock.acquire() lock.acquire() lock.release() @@ -254,6 +255,7 @@ lock.release() lock.release() self.assertRaises(RuntimeError, lock.release) + self.assertRaises(RuntimeError, lock._release_save) def test_different_thread(self): # Cannot release from a different thread diff --git a/Lib/threading.py b/Lib/threading.py --- a/Lib/threading.py +++ b/Lib/threading.py @@ -157,6 +157,8 @@ def _release_save(self): if __debug__: self._note("%s._release_save()", self) + if self._count == 0: + raise RuntimeError("cannot release un-acquired lock") count = self._count self._count = 0 owner = self._owner diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -113,6 +113,9 @@ Library ------- +- Issue #11915: threading.RLock()._release_save() raises a RuntimeError if the + lock was not acquired. + - Issue #11258: Speed up ctypes.util.find_library() under Linux by a factor of 5 to 10. Initial patch by Jonas H. diff --git a/Modules/_threadmodule.c b/Modules/_threadmodule.c --- a/Modules/_threadmodule.c +++ b/Modules/_threadmodule.c @@ -414,6 +414,12 @@ long owner; unsigned long count; + if (self->rlock_count == 0) { + PyErr_SetString(PyExc_RuntimeError, + "cannot release un-acquired lock"); + return NULL; + } + owner = self->rlock_owner; count = self->rlock_count; self->rlock_count = 0; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Apr 24 23:45:27 2011 From: python-checkins at python.org (victor.stinner) Date: Sun, 24 Apr 2011 23:45:27 +0200 Subject: [Python-checkins] cpython: Issue #11005, issue #11915: fix issue number of commit 2c0da1c4f063. Message-ID: http://hg.python.org/cpython/rev/996b9c9dc10a changeset: 69544:996b9c9dc10a user: Victor Stinner date: Sun Apr 24 23:45:23 2011 +0200 summary: Issue #11005, issue #11915: fix issue number of commit 2c0da1c4f063. files: Misc/NEWS | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -113,7 +113,7 @@ Library ------- -- Issue #11915: threading.RLock()._release_save() raises a RuntimeError if the +- Issue #11005: threading.RLock()._release_save() raises a RuntimeError if the lock was not acquired. - Issue #11258: Speed up ctypes.util.find_library() under Linux by a factor -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 25 03:47:49 2011 From: python-checkins at python.org (jesus.cea) Date: Mon, 25 Apr 2011 03:47:49 +0200 Subject: [Python-checkins] cpython (2.7): pybench prep_times calculation error (closes #11895) Message-ID: http://hg.python.org/cpython/rev/e4fcfb8066ff changeset: 69545:e4fcfb8066ff branch: 2.7 parent: 69540:c64c41974d1f user: Jesus Cea date: Mon Apr 25 03:20:54 2011 +0200 summary: pybench prep_times calculation error (closes #11895) files: Misc/ACKS | 1 + Tools/pybench/pybench.py | 2 +- 2 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -795,6 +795,7 @@ Monty Taylor Amy Taylor Anatoly Techtonik +Mikhail Terekhov Tobias Thelen James Thomas Robin Thomas diff --git a/Tools/pybench/pybench.py b/Tools/pybench/pybench.py --- a/Tools/pybench/pybench.py +++ b/Tools/pybench/pybench.py @@ -278,7 +278,7 @@ for i in calibration_loops: pass t = timer() - t - prep_times.append(t) + prep_times.append(t / CALIBRATION_LOOPS) min_prep_time = min(prep_times) if _debug: print -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 25 03:47:54 2011 From: python-checkins at python.org (jesus.cea) Date: Mon, 25 Apr 2011 03:47:54 +0200 Subject: [Python-checkins] cpython (3.1): pybench prep_times calculation error (closes #11895) Message-ID: http://hg.python.org/cpython/rev/7569870a8236 changeset: 69546:7569870a8236 branch: 3.1 parent: 69499:b20d3f54366c user: Jesus Cea date: Mon Apr 25 03:24:08 2011 +0200 summary: pybench prep_times calculation error (closes #11895) files: Misc/ACKS | 1 + Tools/pybench/pybench.py | 2 +- 2 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -794,6 +794,7 @@ Steven Taschuk Monty Taylor Amy Taylor +Mikhail Terekhov Tobias Thelen James Thomas Robin Thomas diff --git a/Tools/pybench/pybench.py b/Tools/pybench/pybench.py --- a/Tools/pybench/pybench.py +++ b/Tools/pybench/pybench.py @@ -276,7 +276,7 @@ for i in calibration_loops: pass t = timer() - t - prep_times.append(t) + prep_times.append(t / CALIBRATION_LOOPS) min_prep_time = min(prep_times) if _debug: print() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 25 03:47:57 2011 From: python-checkins at python.org (jesus.cea) Date: Mon, 25 Apr 2011 03:47:57 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): pybench prep_times calculation error (closes #11895) Message-ID: http://hg.python.org/cpython/rev/66ef5e844e6c changeset: 69547:66ef5e844e6c branch: 3.2 parent: 69541:b0385ec55e7e parent: 69546:7569870a8236 user: Jesus Cea date: Mon Apr 25 03:25:37 2011 +0200 summary: pybench prep_times calculation error (closes #11895) files: Misc/ACKS | 1 + Tools/pybench/pybench.py | 2 +- 2 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -852,6 +852,7 @@ Monty Taylor Amy Taylor Anatoly Techtonik +Mikhail Terekhov Tobias Thelen James Thomas Robin Thomas diff --git a/Tools/pybench/pybench.py b/Tools/pybench/pybench.py --- a/Tools/pybench/pybench.py +++ b/Tools/pybench/pybench.py @@ -276,7 +276,7 @@ for i in calibration_loops: pass t = timer() - t - prep_times.append(t) + prep_times.append(t / CALIBRATION_LOOPS) min_prep_time = min(prep_times) if _debug: print() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 25 03:48:00 2011 From: python-checkins at python.org (jesus.cea) Date: Mon, 25 Apr 2011 03:48:00 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Correctly merging #9319 into 3.3? Message-ID: http://hg.python.org/cpython/rev/bb62908896fe changeset: 69548:bb62908896fe parent: 69544:996b9c9dc10a parent: 69541:b0385ec55e7e user: Jesus Cea date: Mon Apr 25 03:46:43 2011 +0200 summary: Correctly merging #9319 into 3.3? files: Lib/test/test_imp.py | 4 ++++ Parser/tokenizer.c | 19 +++++++++++++------ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/Lib/test/test_imp.py b/Lib/test/test_imp.py --- a/Lib/test/test_imp.py +++ b/Lib/test/test_imp.py @@ -176,6 +176,10 @@ support.unlink(init_file_name + ext) support.rmtree(test_package_name) + def test_issue9319(self): + self.assertRaises(SyntaxError, + imp.find_module, "test/badsyntax_pep3120") + class ReloadTests(unittest.TestCase): diff --git a/Parser/tokenizer.c b/Parser/tokenizer.c --- a/Parser/tokenizer.c +++ b/Parser/tokenizer.c @@ -585,12 +585,19 @@ if (badchar) { /* Need to add 1 to the line number, since this line has not been counted, yet. */ - PyErr_Format(PyExc_SyntaxError, - "Non-UTF-8 code starting with '\\x%.2x' " - "in file %U on line %i, " - "but no encoding declared; " - "see http://python.org/dev/peps/pep-0263/ for details", - badchar, tok->filename, tok->lineno + 1); + if (tok->filename != NULL) + filename = PyUnicode_DecodeFSDefault(tok->filename); + else + filename = PyUnicode_FromString(""); + if (filename != NULL) { + PyErr_Format(PyExc_SyntaxError, + "Non-UTF-8 code starting with '\\x%.2x' " + "in file %U on line %i, " + "but no encoding declared; " + "see http://python.org/dev/peps/pep-0263/ for details", + badchar, filename, tok->lineno + 1); + Py_DECREF(filename); + } return error_ret(tok); } #endif -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 25 03:48:02 2011 From: python-checkins at python.org (jesus.cea) Date: Mon, 25 Apr 2011 03:48:02 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): pybench prep_times calculation error (closes #11895) Message-ID: http://hg.python.org/cpython/rev/8a277949d904 changeset: 69549:8a277949d904 parent: 69548:bb62908896fe parent: 69547:66ef5e844e6c user: Jesus Cea date: Mon Apr 25 03:47:23 2011 +0200 summary: pybench prep_times calculation error (closes #11895) files: Misc/ACKS | 1 + Tools/pybench/pybench.py | 2 +- 2 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -859,6 +859,7 @@ Monty Taylor Amy Taylor Anatoly Techtonik +Mikhail Terekhov Tobias Thelen James Thomas Robin Thomas diff --git a/Tools/pybench/pybench.py b/Tools/pybench/pybench.py --- a/Tools/pybench/pybench.py +++ b/Tools/pybench/pybench.py @@ -276,7 +276,7 @@ for i in calibration_loops: pass t = timer() - t - prep_times.append(t) + prep_times.append(t / CALIBRATION_LOOPS) min_prep_time = min(prep_times) if _debug: print() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 25 04:04:03 2011 From: python-checkins at python.org (jesus.cea) Date: Mon, 25 Apr 2011 04:04:03 +0200 Subject: [Python-checkins] cpython: Revert bb62908896fe, but keep the test Message-ID: http://hg.python.org/cpython/rev/4658762a77cf changeset: 69550:4658762a77cf user: Jesus Cea date: Mon Apr 25 04:03:58 2011 +0200 summary: Revert bb62908896fe, but keep the test files: Parser/tokenizer.c | 19 ++++++------------- 1 files changed, 6 insertions(+), 13 deletions(-) diff --git a/Parser/tokenizer.c b/Parser/tokenizer.c --- a/Parser/tokenizer.c +++ b/Parser/tokenizer.c @@ -585,19 +585,12 @@ if (badchar) { /* Need to add 1 to the line number, since this line has not been counted, yet. */ - if (tok->filename != NULL) - filename = PyUnicode_DecodeFSDefault(tok->filename); - else - filename = PyUnicode_FromString(""); - if (filename != NULL) { - PyErr_Format(PyExc_SyntaxError, - "Non-UTF-8 code starting with '\\x%.2x' " - "in file %U on line %i, " - "but no encoding declared; " - "see http://python.org/dev/peps/pep-0263/ for details", - badchar, filename, tok->lineno + 1); - Py_DECREF(filename); - } + PyErr_Format(PyExc_SyntaxError, + "Non-UTF-8 code starting with '\\x%.2x' " + "in file %U on line %i, " + "but no encoding declared; " + "see http://python.org/dev/peps/pep-0263/ for details", + badchar, tok->filename, tok->lineno + 1); return error_ret(tok); } #endif -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Mon Apr 25 04:57:22 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Mon, 25 Apr 2011 04:57:22 +0200 Subject: [Python-checkins] Daily reference leaks (996b9c9dc10a): sum=0 Message-ID: results for 996b9c9dc10a on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogM9uaro', '-x'] From python-checkins at python.org Mon Apr 25 16:24:06 2011 From: python-checkins at python.org (victor.stinner) Date: Mon, 25 Apr 2011 16:24:06 +0200 Subject: [Python-checkins] peps: Unsupport OS/2 and VMS Message-ID: http://hg.python.org/peps/rev/3464257c9462 changeset: 3870:3464257c9462 user: Victor Stinner date: Mon Apr 25 16:24:15 2011 +0200 summary: Unsupport OS/2 and VMS files: pep-0011.txt | 11 +++++++++-- 1 files changed, 9 insertions(+), 2 deletions(-) diff --git a/pep-0011.txt b/pep-0011.txt --- a/pep-0011.txt +++ b/pep-0011.txt @@ -161,13 +161,20 @@ Code removed in: Python 3.3 Name: OSF* systems (issue 8606) - Unsupported in: Python 3.2 + Unsupported in: Python 3.2 Code removed in: Python 3.3 + Name: OS/2 + Unsupported in: Python 3.3 + Code removed in: Python 3.4 + + Name: VMS + Unsupported in: Python 3.3 + Code removed in: Python 3.4 + Platform Maintainers Cygwin Jason Tishler (jason at tishler.net) - OS2/EMX Andrew MacIntyre (andymac at bullseye.apana.org.au) More TBD. Copyright -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Mon Apr 25 19:01:34 2011 From: python-checkins at python.org (alexander.belopolsky) Date: Mon, 25 Apr 2011 19:01:34 +0200 Subject: [Python-checkins] cpython: Issue #2736: Documented how to compute seconds since epoch. Message-ID: http://hg.python.org/cpython/rev/b55eac85e39c changeset: 69551:b55eac85e39c user: Alexander Belopolsky date: Mon Apr 25 13:00:40 2011 -0400 summary: Issue #2736: Documented how to compute seconds since epoch. files: Doc/library/datetime.rst | 16 ++++++++++++++++ 1 files changed, 16 insertions(+), 0 deletions(-) diff --git a/Doc/library/datetime.rst b/Doc/library/datetime.rst --- a/Doc/library/datetime.rst +++ b/Doc/library/datetime.rst @@ -721,6 +721,22 @@ It's common for this to be restricted to years in 1970 through 2038. See also :meth:`fromtimestamp`. + On the POSIX compliant platforms, ``utcfromtimestamp(timestamp)`` + is equivalent to the following expression:: + + datetime(1970, 1, 1) + timedelta(seconds=timestamp) + + There is no method to obtain the timestamp from a :class:`datetime` + instance, but POSIX timestamp corresponding to a :class:`datetime` + instance ``dt`` can be easily calculated as follows. For a naive + ``dt``:: + + timestamp = (dt - datetime(1970, 1, 1)) / timedelta(seconds=1) + + And for an aware ``dt``:: + + timestamp = (dt - datetime(1970, 1, 1, tzinfo=timezone.utc)) / timedelta(seconds=1) + .. classmethod:: datetime.fromordinal(ordinal) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 25 19:16:19 2011 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 25 Apr 2011 19:16:19 +0200 Subject: [Python-checkins] cpython: Issue #11856: Speed up parsing of JSON numbers. Message-ID: http://hg.python.org/cpython/rev/d60f9d9983bb changeset: 69552:d60f9d9983bb user: Antoine Pitrou date: Mon Apr 25 19:16:06 2011 +0200 summary: Issue #11856: Speed up parsing of JSON numbers. files: Misc/NEWS | 2 + Modules/_json.c | 46 ++++++++++++++++++++++++------------ 2 files changed, 33 insertions(+), 15 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -113,6 +113,8 @@ Library ------- +- Issue #11856: Speed up parsing of JSON numbers. + - Issue #11005: threading.RLock()._release_save() raises a RuntimeError if the lock was not acquired. diff --git a/Modules/_json.c b/Modules/_json.c --- a/Modules/_json.c +++ b/Modules/_json.c @@ -842,7 +842,8 @@ Py_ssize_t idx = start; int is_float = 0; PyObject *rval; - PyObject *numstr; + PyObject *numstr = NULL; + PyObject *custom_func; /* read a sign if it's there, make sure it's not the end of the string */ if (str[idx] == '-') { @@ -895,22 +896,37 @@ } } - /* copy the section we determined to be a number */ - numstr = PyUnicode_FromUnicode(&str[start], idx - start); - if (numstr == NULL) - return NULL; - if (is_float) { - /* parse as a float using a fast path if available, otherwise call user defined method */ - if (s->parse_float != (PyObject *)&PyFloat_Type) { - rval = PyObject_CallFunctionObjArgs(s->parse_float, numstr, NULL); - } - else { - rval = PyFloat_FromString(numstr); - } + if (is_float && s->parse_float != (PyObject *)&PyFloat_Type) + custom_func = s->parse_float; + else if (!is_float && s->parse_int != (PyObject *) &PyLong_Type) + custom_func = s->parse_int; + else + custom_func = NULL; + + if (custom_func) { + /* copy the section we determined to be a number */ + numstr = PyUnicode_FromUnicode(&str[start], idx - start); + if (numstr == NULL) + return NULL; + rval = PyObject_CallFunctionObjArgs(custom_func, numstr, NULL); } else { - /* no fast path for unicode -> int, just call */ - rval = PyObject_CallFunctionObjArgs(s->parse_int, numstr, NULL); + Py_ssize_t i, n; + char *buf; + /* Straight conversion to ASCII, to avoid costly conversion of + decimal unicode digits (which cannot appear here) */ + n = idx - start; + numstr = PyBytes_FromStringAndSize(NULL, n); + if (numstr == NULL) + return NULL; + buf = PyBytes_AS_STRING(numstr); + for (i = 0; i < n; i++) { + buf[i] = (char) str[i + start]; + } + if (is_float) + rval = PyFloat_FromString(numstr); + else + rval = PyLong_FromString(buf, NULL, 10); } Py_DECREF(numstr); *next_idx_ptr = idx; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 25 21:23:40 2011 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 25 Apr 2011 21:23:40 +0200 Subject: [Python-checkins] cpython (3.2): Issue #10914: Add a minimal embedding test to test_capi. Message-ID: http://hg.python.org/cpython/rev/d195ff5c44f4 changeset: 69553:d195ff5c44f4 branch: 3.2 parent: 69547:66ef5e844e6c user: Antoine Pitrou date: Mon Apr 25 21:21:07 2011 +0200 summary: Issue #10914: Add a minimal embedding test to test_capi. files: .hgignore | 1 + Lib/test/test_capi.py | 35 +++++++++++++++++++- Makefile.pre.in | 5 ++- Modules/_testembed.c | 52 +++++++++++++++++++++++++++++++ 4 files changed, 89 insertions(+), 4 deletions(-) diff --git a/.hgignore b/.hgignore --- a/.hgignore +++ b/.hgignore @@ -64,3 +64,4 @@ PCbuild/*.bsc PCbuild/Win32-temp-* __pycache__ +Modules/_testembed diff --git a/Lib/test/test_capi.py b/Lib/test/test_capi.py --- a/Lib/test/test_capi.py +++ b/Lib/test/test_capi.py @@ -2,6 +2,7 @@ # these are all functions _testcapi exports whose name begins with 'test_'. from __future__ import with_statement +import os import random import subprocess import sys @@ -141,8 +142,38 @@ def test(self): self.assertEqual(_testcapi.argparsing("Hello", "World"), 1) + +class EmbeddingTest(unittest.TestCase): + + def test_subinterps(self): + # XXX only tested under Unix checkouts + basepath = os.path.dirname(os.path.dirname(os.path.dirname(__file__))) + oldcwd = os.getcwd() + # This is needed otherwise we get a fatal error: + # "Py_Initialize: Unable to get the locale encoding + # LookupError: no codec search functions registered: can't find encoding" + os.chdir(basepath) + try: + exe = os.path.join(basepath, "Modules", "_testembed") + if not os.path.exists(exe): + self.skipTest("%r doesn't exist" % exe) + p = subprocess.Popen([exe], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + (out, err) = p.communicate() + self.assertEqual(p.returncode, 0, + "bad returncode %d, stderr is %r" % + (p.returncode, err)) + if support.verbose: + print() + print(out.decode('latin1')) + print(err.decode('latin1')) + finally: + os.chdir(oldcwd) + + def test_main(): - support.run_unittest(CAPITest) + support.run_unittest(CAPITest, TestPendingCalls, Test6012, EmbeddingTest) for name in dir(_testcapi): if name.startswith('test_'): @@ -177,8 +208,6 @@ t.start() t.join() - support.run_unittest(TestPendingCalls, Test6012) - if __name__ == "__main__": test_main() diff --git a/Makefile.pre.in b/Makefile.pre.in --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -394,7 +394,7 @@ # Default target all: build_all -build_all: $(BUILDPYTHON) oldsharedmods sharedmods gdbhooks +build_all: $(BUILDPYTHON) oldsharedmods sharedmods gdbhooks Modules/_testembed # Compile a binary with gcc profile guided optimization. profile-opt: @@ -539,6 +539,9 @@ echo "-----------------------------------------------"; \ fi +Modules/_testembed: Modules/_testembed.o $(LIBRARY) $(LDLIBRARY) $(PY3LIBRARY) + $(LINKCC) $(PY_LDFLAGS) $(LINKFORSHARED) -o $@ Modules/_testembed.o $(BLDLIBRARY) $(LIBS) $(MODLIBS) $(SYSLIBS) $(LDLAST) + ############################################################################ # Special rules for object files diff --git a/Modules/_testembed.c b/Modules/_testembed.c new file mode 100644 --- /dev/null +++ b/Modules/_testembed.c @@ -0,0 +1,52 @@ +#include +#include + +void print_subinterp(void) +{ + /* Just output some debug stuff */ + PyThreadState *ts = PyThreadState_Get(); + printf("interp %p, thread state %p: ", ts->interp, ts); + fflush(stdout); + PyRun_SimpleString( + "import sys;" + "print('id(modules) =', id(sys.modules));" + "sys.stdout.flush()" + ); +} + +int main(int argc, char *argv[]) +{ + PyThreadState *mainstate, *substate; + PyGILState_STATE gilstate; + int i, j; + + for (i=0; i<3; i++) { + printf("--- Pass %d ---\n", i); + /* HACK: the "./" at front avoids a search along the PATH in + Modules/getpath.c */ + Py_SetProgramName(L"./_testembed"); + Py_Initialize(); + mainstate = PyThreadState_Get(); + + PyEval_InitThreads(); + PyEval_ReleaseThread(mainstate); + + gilstate = PyGILState_Ensure(); + print_subinterp(); + PyThreadState_Swap(NULL); + + for (j=0; j<3; j++) { + substate = Py_NewInterpreter(); + print_subinterp(); + Py_EndInterpreter(substate); + } + + PyThreadState_Swap(mainstate); + print_subinterp(); + PyGILState_Release(gilstate); + + PyEval_RestoreThread(mainstate); + Py_Finalize(); + } + return 0; +} -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 25 21:23:41 2011 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 25 Apr 2011 21:23:41 +0200 Subject: [Python-checkins] cpython (3.2): Issue #10914: add NEWS item. Message-ID: http://hg.python.org/cpython/rev/77cf9e4b144b changeset: 69554:77cf9e4b144b branch: 3.2 user: Antoine Pitrou date: Mon Apr 25 21:22:04 2011 +0200 summary: Issue #10914: add NEWS item. files: Misc/NEWS | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -281,6 +281,8 @@ Tests ----- +- Issue #10914: Add a minimal embedding test to test_capi. + - Issue #11790: Fix sporadic failures in test_multiprocessing.WithProcessesTestCondition. - Fix possible "file already exists" error when running the tests in parallel. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 25 21:23:42 2011 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 25 Apr 2011 21:23:42 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Issue #10914: Add a minimal embedding test to test_capi. Message-ID: http://hg.python.org/cpython/rev/ef1ad39e3c40 changeset: 69555:ef1ad39e3c40 parent: 69552:d60f9d9983bb parent: 69554:77cf9e4b144b user: Antoine Pitrou date: Mon Apr 25 21:23:26 2011 +0200 summary: Issue #10914: Add a minimal embedding test to test_capi. files: .hgignore | 1 + Lib/test/test_capi.py | 35 +++++++++++++++++++- Makefile.pre.in | 5 ++- Misc/NEWS | 2 + Modules/_testembed.c | 52 +++++++++++++++++++++++++++++++ 5 files changed, 91 insertions(+), 4 deletions(-) diff --git a/.hgignore b/.hgignore --- a/.hgignore +++ b/.hgignore @@ -69,3 +69,4 @@ PCbuild/Win32-temp-* PCbuild/x64-temp-* __pycache__ +Modules/_testembed diff --git a/Lib/test/test_capi.py b/Lib/test/test_capi.py --- a/Lib/test/test_capi.py +++ b/Lib/test/test_capi.py @@ -2,6 +2,7 @@ # these are all functions _testcapi exports whose name begins with 'test_'. from __future__ import with_statement +import os import random import subprocess import sys @@ -141,8 +142,38 @@ def test(self): self.assertEqual(_testcapi.argparsing("Hello", "World"), 1) + +class EmbeddingTest(unittest.TestCase): + + def test_subinterps(self): + # XXX only tested under Unix checkouts + basepath = os.path.dirname(os.path.dirname(os.path.dirname(__file__))) + oldcwd = os.getcwd() + # This is needed otherwise we get a fatal error: + # "Py_Initialize: Unable to get the locale encoding + # LookupError: no codec search functions registered: can't find encoding" + os.chdir(basepath) + try: + exe = os.path.join(basepath, "Modules", "_testembed") + if not os.path.exists(exe): + self.skipTest("%r doesn't exist" % exe) + p = subprocess.Popen([exe], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + (out, err) = p.communicate() + self.assertEqual(p.returncode, 0, + "bad returncode %d, stderr is %r" % + (p.returncode, err)) + if support.verbose: + print() + print(out.decode('latin1')) + print(err.decode('latin1')) + finally: + os.chdir(oldcwd) + + def test_main(): - support.run_unittest(CAPITest) + support.run_unittest(CAPITest, TestPendingCalls, Test6012, EmbeddingTest) for name in dir(_testcapi): if name.startswith('test_'): @@ -177,8 +208,6 @@ t.start() t.join() - support.run_unittest(TestPendingCalls, Test6012) - if __name__ == "__main__": test_main() diff --git a/Makefile.pre.in b/Makefile.pre.in --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -394,7 +394,7 @@ # Default target all: build_all -build_all: $(BUILDPYTHON) oldsharedmods sharedmods gdbhooks +build_all: $(BUILDPYTHON) oldsharedmods sharedmods gdbhooks Modules/_testembed # Compile a binary with gcc profile guided optimization. profile-opt: @@ -539,6 +539,9 @@ echo "-----------------------------------------------"; \ fi +Modules/_testembed: Modules/_testembed.o $(LIBRARY) $(LDLIBRARY) $(PY3LIBRARY) + $(LINKCC) $(PY_LDFLAGS) $(LINKFORSHARED) -o $@ Modules/_testembed.o $(BLDLIBRARY) $(LIBS) $(MODLIBS) $(SYSLIBS) $(LDLAST) + ############################################################################ # Special rules for object files diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -504,6 +504,8 @@ Tests ----- +- Issue #10914: Add a minimal embedding test to test_capi. + - Issue #11223: Skip test_lock_acquire_interruption() and test_rlock_acquire_interruption() of test_threadsignals if a thread lock is implemented using a POSIX mutex and a POSIX condition variable. A POSIX diff --git a/Modules/_testembed.c b/Modules/_testembed.c new file mode 100644 --- /dev/null +++ b/Modules/_testembed.c @@ -0,0 +1,52 @@ +#include +#include + +void print_subinterp(void) +{ + /* Just output some debug stuff */ + PyThreadState *ts = PyThreadState_Get(); + printf("interp %p, thread state %p: ", ts->interp, ts); + fflush(stdout); + PyRun_SimpleString( + "import sys;" + "print('id(modules) =', id(sys.modules));" + "sys.stdout.flush()" + ); +} + +int main(int argc, char *argv[]) +{ + PyThreadState *mainstate, *substate; + PyGILState_STATE gilstate; + int i, j; + + for (i=0; i<3; i++) { + printf("--- Pass %d ---\n", i); + /* HACK: the "./" at front avoids a search along the PATH in + Modules/getpath.c */ + Py_SetProgramName(L"./_testembed"); + Py_Initialize(); + mainstate = PyThreadState_Get(); + + PyEval_InitThreads(); + PyEval_ReleaseThread(mainstate); + + gilstate = PyGILState_Ensure(); + print_subinterp(); + PyThreadState_Swap(NULL); + + for (j=0; j<3; j++) { + substate = Py_NewInterpreter(); + print_subinterp(); + Py_EndInterpreter(substate); + } + + PyThreadState_Swap(mainstate); + print_subinterp(); + PyGILState_Release(gilstate); + + PyEval_RestoreThread(mainstate); + Py_Finalize(); + } + return 0; +} -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 25 21:40:03 2011 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 25 Apr 2011 21:40:03 +0200 Subject: [Python-checkins] cpython (3.2): Issue #11919: try to fix test_imp failure on some buildbots. Message-ID: http://hg.python.org/cpython/rev/2f2c7eb27437 changeset: 69556:2f2c7eb27437 branch: 3.2 parent: 69554:77cf9e4b144b user: Antoine Pitrou date: Mon Apr 25 21:39:49 2011 +0200 summary: Issue #11919: try to fix test_imp failure on some buildbots. files: Lib/test/test_imp.py | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_imp.py b/Lib/test/test_imp.py --- a/Lib/test/test_imp.py +++ b/Lib/test/test_imp.py @@ -171,8 +171,9 @@ support.rmtree(test_package_name) def test_issue9319(self): + path = os.path.dirname(__file__) self.assertRaises(SyntaxError, - imp.find_module, "test/badsyntax_pep3120") + imp.find_module, "badsyntax_pep3120", [path]) class ReloadTests(unittest.TestCase): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 25 21:46:08 2011 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 25 Apr 2011 21:46:08 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Issue #11919: try to fix test_imp failure on some buildbots. Message-ID: http://hg.python.org/cpython/rev/0c70c24750fd changeset: 69557:0c70c24750fd parent: 69555:ef1ad39e3c40 parent: 69556:2f2c7eb27437 user: Antoine Pitrou date: Mon Apr 25 21:46:04 2011 +0200 summary: Issue #11919: try to fix test_imp failure on some buildbots. files: Lib/test/test_imp.py | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_imp.py b/Lib/test/test_imp.py --- a/Lib/test/test_imp.py +++ b/Lib/test/test_imp.py @@ -177,8 +177,9 @@ support.rmtree(test_package_name) def test_issue9319(self): + path = os.path.dirname(__file__) self.assertRaises(SyntaxError, - imp.find_module, "test/badsyntax_pep3120") + imp.find_module, "badsyntax_pep3120", [path]) class ReloadTests(unittest.TestCase): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 25 22:14:59 2011 From: python-checkins at python.org (r.david.murray) Date: Mon, 25 Apr 2011 22:14:59 +0200 Subject: [Python-checkins] cpython (2.7): #11901: add description of how bitfields are laid out to hexversion docs Message-ID: http://hg.python.org/cpython/rev/48758cd0769b changeset: 69558:48758cd0769b branch: 2.7 parent: 69545:e4fcfb8066ff user: R David Murray date: Mon Apr 25 16:10:18 2011 -0400 summary: #11901: add description of how bitfields are laid out to hexversion docs Patch by Sijin Joseph. files: Doc/library/sys.rst | 24 ++++++++++++++++++++++++ Misc/ACKS | 1 + 2 files changed, 25 insertions(+), 0 deletions(-) diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -562,6 +562,30 @@ ``version_info`` value may be used for a more human-friendly encoding of the same information. + The ``hexversion`` is a 32-bit number with the following layout + + +-------------------------+------------------------------------------------+ + | bits (big endian order) | meaning | + +=========================+================================================+ + | :const:`1-8` | ``PY_MAJOR_VERSION`` (the ``2`` in | + | | ``2.1.0a3``) | + +-------------------------+------------------------------------------------+ + | :const:`9-16` | ``PY_MINOR_VERSION`` (the ``1`` in | + | | ``2.1.0a3``) | + +-------------------------+------------------------------------------------+ + | :const:`17-24` | ``PY_MICRO_VERSION`` (the ``0`` in | + | | ``2.1.0a3``) | + +-------------------------+------------------------------------------------+ + | :const:`25-28` | ``PY_RELEASE_LEVEL`` (``0xA`` for alpha, | + | | ``0xB`` for beta, ``0xC`` for gamma and | + | | ``0xF`` for final) | + +-------------------------+------------------------------------------------+ + | :const:`29-32` | ``PY_RELEASE_SERIAL`` (the ``3`` in | + | | ``2.1.0a3``) | + +-------------------------+------------------------------------------------+ + + thus ``2.1.0a3`` is hexversion ``0x020100a3`` + .. versionadded:: 1.5.2 diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -411,6 +411,7 @@ Lucas de Jonge John Jorgensen Jens B. Jorgensen +Sijin Joseph Andreas Jung Tattoo Mabonzo K. Bob Kahn -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 25 22:15:02 2011 From: python-checkins at python.org (r.david.murray) Date: Mon, 25 Apr 2011 22:15:02 +0200 Subject: [Python-checkins] cpython (3.1): #11901: add description of how bitfields are laid out to hexversion docs Message-ID: http://hg.python.org/cpython/rev/b84384fbdbf0 changeset: 69559:b84384fbdbf0 branch: 3.1 parent: 69546:7569870a8236 user: R David Murray date: Mon Apr 25 16:12:26 2011 -0400 summary: #11901: add description of how bitfields are laid out to hexversion docs Patch by Sijin Joseph. files: Doc/library/sys.rst | 23 +++++++++++++++++++++++ Misc/ACKS | 1 + 2 files changed, 24 insertions(+), 0 deletions(-) diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -450,6 +450,29 @@ ``version_info`` value may be used for a more human-friendly encoding of the same information. + The ``hexversion`` is a 32-bit number with the following layout + + +-------------------------+------------------------------------------------+ + | bits (big endian order) | meaning | + +=========================+================================================+ + | :const:`1-8` | ``PY_MAJOR_VERSION`` (the ``2`` in | + | | ``2.1.0a3``) | + +-------------------------+------------------------------------------------+ + | :const:`9-16` | ``PY_MINOR_VERSION`` (the ``1`` in | + | | ``2.1.0a3``) | + +-------------------------+------------------------------------------------+ + | :const:`17-24` | ``PY_MICRO_VERSION`` (the ``0`` in | + | | ``2.1.0a3``) | + +-------------------------+------------------------------------------------+ + | :const:`25-28` | ``PY_RELEASE_LEVEL`` (``0xA`` for alpha, | + | | ``0xB`` for beta, ``0xC`` for gamma and | + | | ``0xF`` for final) | + +-------------------------+------------------------------------------------+ + | :const:`29-32` | ``PY_RELEASE_SERIAL`` (the ``3`` in | + | | ``2.1.0a3``) | + +-------------------------+------------------------------------------------+ + + thus ``2.1.0a3`` is hexversion ``0x020100a3`` .. data:: int_info diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -411,6 +411,7 @@ Lucas de Jonge John Jorgensen Jens B. Jorgensen +Sijin Joseph Andreas Jung Tattoo Mabonzo K. Bob Kahn -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 25 22:15:10 2011 From: python-checkins at python.org (r.david.murray) Date: Mon, 25 Apr 2011 22:15:10 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): Merge #11901: add description of how bitfields are laid out to hexversion docs Message-ID: http://hg.python.org/cpython/rev/cca4c92bf337 changeset: 69560:cca4c92bf337 branch: 3.2 parent: 69556:2f2c7eb27437 parent: 69559:b84384fbdbf0 user: R David Murray date: Mon Apr 25 16:13:54 2011 -0400 summary: Merge #11901: add description of how bitfields are laid out to hexversion docs Patch by Sijin Joseph. files: Doc/library/sys.rst | 23 +++++++++++++++++++++++ Misc/ACKS | 1 + 2 files changed, 24 insertions(+), 0 deletions(-) diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -552,6 +552,29 @@ ``version_info`` value may be used for a more human-friendly encoding of the same information. + The ``hexversion`` is a 32-bit number with the following layout + + +-------------------------+------------------------------------------------+ + | bits (big endian order) | meaning | + +=========================+================================================+ + | :const:`1-8` | ``PY_MAJOR_VERSION`` (the ``2`` in | + | | ``2.1.0a3``) | + +-------------------------+------------------------------------------------+ + | :const:`9-16` | ``PY_MINOR_VERSION`` (the ``1`` in | + | | ``2.1.0a3``) | + +-------------------------+------------------------------------------------+ + | :const:`17-24` | ``PY_MICRO_VERSION`` (the ``0`` in | + | | ``2.1.0a3``) | + +-------------------------+------------------------------------------------+ + | :const:`25-28` | ``PY_RELEASE_LEVEL`` (``0xA`` for alpha, | + | | ``0xB`` for beta, ``0xC`` for gamma and | + | | ``0xF`` for final) | + +-------------------------+------------------------------------------------+ + | :const:`29-32` | ``PY_RELEASE_SERIAL`` (the ``3`` in | + | | ``2.1.0a3``) | + +-------------------------+------------------------------------------------+ + + thus ``2.1.0a3`` is hexversion ``0x020100a3`` .. data:: int_info diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -442,6 +442,7 @@ Lucas de Jonge John Jorgensen Jens B. Jorgensen +Sijin Joseph Andreas Jung Tattoo Mabonzo K. Bob Kahn -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Apr 25 22:15:12 2011 From: python-checkins at python.org (r.david.murray) Date: Mon, 25 Apr 2011 22:15:12 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge #11901: add description of how bitfields are laid out to hexversion docs Message-ID: http://hg.python.org/cpython/rev/07149918bce1 changeset: 69561:07149918bce1 parent: 69557:0c70c24750fd parent: 69560:cca4c92bf337 user: R David Murray date: Mon Apr 25 16:14:26 2011 -0400 summary: Merge #11901: add description of how bitfields are laid out to hexversion docs Patch by Sijin Joseph. files: Doc/library/sys.rst | 23 +++++++++++++++++++++++ Misc/ACKS | 1 + 2 files changed, 24 insertions(+), 0 deletions(-) diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -540,6 +540,29 @@ ``version_info`` value may be used for a more human-friendly encoding of the same information. + The ``hexversion`` is a 32-bit number with the following layout + + +-------------------------+------------------------------------------------+ + | bits (big endian order) | meaning | + +=========================+================================================+ + | :const:`1-8` | ``PY_MAJOR_VERSION`` (the ``2`` in | + | | ``2.1.0a3``) | + +-------------------------+------------------------------------------------+ + | :const:`9-16` | ``PY_MINOR_VERSION`` (the ``1`` in | + | | ``2.1.0a3``) | + +-------------------------+------------------------------------------------+ + | :const:`17-24` | ``PY_MICRO_VERSION`` (the ``0`` in | + | | ``2.1.0a3``) | + +-------------------------+------------------------------------------------+ + | :const:`25-28` | ``PY_RELEASE_LEVEL`` (``0xA`` for alpha, | + | | ``0xB`` for beta, ``0xC`` for gamma and | + | | ``0xF`` for final) | + +-------------------------+------------------------------------------------+ + | :const:`29-32` | ``PY_RELEASE_SERIAL`` (the ``3`` in | + | | ``2.1.0a3``) | + +-------------------------+------------------------------------------------+ + + thus ``2.1.0a3`` is hexversion ``0x020100a3`` .. data:: int_info diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -446,6 +446,7 @@ Lucas de Jonge John Jorgensen Jens B. Jorgensen +Sijin Joseph Andreas Jung Tattoo Mabonzo K. Bob Kahn -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Tue Apr 26 04:57:33 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Tue, 26 Apr 2011 04:57:33 +0200 Subject: [Python-checkins] Daily reference leaks (07149918bce1): sum=0 Message-ID: results for 07149918bce1 on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogt69Q8_', '-x'] From python-checkins at python.org Tue Apr 26 05:45:17 2011 From: python-checkins at python.org (ezio.melotti) Date: Tue, 26 Apr 2011 05:45:17 +0200 Subject: [Python-checkins] cpython (2.7): #6780: fix starts/endswith error message to mention that tuples are accepted Message-ID: http://hg.python.org/cpython/rev/3ceeccbc2c3b changeset: 69562:3ceeccbc2c3b branch: 2.7 parent: 69558:48758cd0769b user: Ezio Melotti date: Tue Apr 26 05:12:51 2011 +0300 summary: #6780: fix starts/endswith error message to mention that tuples are accepted too. files: Lib/test/test_str.py | 13 ++++++++++++- Lib/test/test_unicode.py | 11 +++++++++++ Misc/NEWS | 3 +++ Objects/stringobject.c | 12 ++++++++++-- Objects/unicodeobject.c | 13 ++++++++++--- 5 files changed, 46 insertions(+), 6 deletions(-) diff --git a/Lib/test/test_str.py b/Lib/test/test_str.py --- a/Lib/test/test_str.py +++ b/Lib/test/test_str.py @@ -414,7 +414,18 @@ self.assertEqual('Andr\202 x'.decode('ascii', 'replace'), 'Andr\202 x'.decode(encoding='ascii', errors='replace')) - + def test_startswith_endswith_errors(self): + with self.assertRaises(UnicodeDecodeError): + '\xff'.startswith(u'x') + with self.assertRaises(UnicodeDecodeError): + '\xff'.endswith(u'x') + for meth in ('foo'.startswith, 'foo'.endswith): + with self.assertRaises(TypeError) as cm: + meth(['f']) + exc = str(cm.exception) + self.assertIn('unicode', exc) + self.assertIn('str', exc) + self.assertIn('tuple', exc) def test_main(): test_support.run_unittest(StrTest) 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 @@ -442,6 +442,17 @@ return u'\u1234' self.assertEqual('%s' % Wrapper(), u'\u1234') + def test_startswith_endswith_errors(self): + for meth in (u'foo'.startswith, u'foo'.endswith): + with self.assertRaises(UnicodeDecodeError): + meth('\xff') + with self.assertRaises(TypeError) as cm: + meth(['f']) + exc = str(cm.exception) + self.assertIn('unicode', exc) + self.assertIn('str', exc) + self.assertIn('tuple', exc) + @test_support.run_with_locale('LC_ALL', 'de_DE', 'fr_FR') def test_format_float(self): # should not format with a comma, but always with C locale diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -9,6 +9,9 @@ Core and Builtins ----------------- +- Issue #6780: fix starts/endswith error message to mention that tuples are + accepted too. + - Issue #5057: fix a bug in the peepholer that led to non-portable pyc files between narrow and wide builds while optimizing BINARY_SUBSCR on non-BMP chars (e.g. u"\U00012345"[0]). diff --git a/Objects/stringobject.c b/Objects/stringobject.c --- a/Objects/stringobject.c +++ b/Objects/stringobject.c @@ -2918,8 +2918,12 @@ Py_RETURN_FALSE; } result = _string_tailmatch(self, subobj, start, end, -1); - if (result == -1) + if (result == -1) { + if (PyErr_ExceptionMatches(PyExc_TypeError)) + PyErr_Format(PyExc_TypeError, "startswith first arg must be str, " + "unicode, or tuple, not %s", Py_TYPE(subobj)->tp_name); return NULL; + } else return PyBool_FromLong(result); } @@ -2958,8 +2962,12 @@ Py_RETURN_FALSE; } result = _string_tailmatch(self, subobj, start, end, +1); - if (result == -1) + if (result == -1) { + if (PyErr_ExceptionMatches(PyExc_TypeError)) + PyErr_Format(PyExc_TypeError, "endswith first arg must be str, " + "unicode, or tuple, not %s", Py_TYPE(subobj)->tp_name); return NULL; + } else return PyBool_FromLong(result); } diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -7666,8 +7666,12 @@ Py_RETURN_FALSE; } substring = (PyUnicodeObject *)PyUnicode_FromObject(subobj); - if (substring == NULL) + if (substring == NULL) { + if (PyErr_ExceptionMatches(PyExc_TypeError)) + PyErr_Format(PyExc_TypeError, "startswith first arg must be str, " + "unicode, or tuple, not %s", Py_TYPE(subobj)->tp_name); return NULL; + } result = tailmatch(self, substring, start, end, -1); Py_DECREF(substring); return PyBool_FromLong(result); @@ -7710,9 +7714,12 @@ Py_RETURN_FALSE; } substring = (PyUnicodeObject *)PyUnicode_FromObject(subobj); - if (substring == NULL) + if (substring == NULL) { + if (PyErr_ExceptionMatches(PyExc_TypeError)) + PyErr_Format(PyExc_TypeError, "endswith first arg must be str, " + "unicode, or tuple, not %s", Py_TYPE(subobj)->tp_name); return NULL; - + } result = tailmatch(self, substring, start, end, +1); Py_DECREF(substring); return PyBool_FromLong(result); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 26 05:45:24 2011 From: python-checkins at python.org (ezio.melotti) Date: Tue, 26 Apr 2011 05:45:24 +0200 Subject: [Python-checkins] cpython (3.1): #6780: fix starts/endswith error message to mention that tuples are accepted Message-ID: http://hg.python.org/cpython/rev/bcbf8c3c4a88 changeset: 69563:bcbf8c3c4a88 branch: 3.1 parent: 69559:b84384fbdbf0 user: Ezio Melotti date: Tue Apr 26 06:09:45 2011 +0300 summary: #6780: fix starts/endswith error message to mention that tuples are accepted too. files: Lib/test/test_bytes.py | 16 ++++++++++++++++ Lib/test/test_unicode.py | 11 +++++++++++ Misc/NEWS | 3 +++ Objects/bytearrayobject.c | 16 ++++++++++++---- Objects/bytesobject.c | 12 ++++++++++-- Objects/unicodeobject.c | 25 ++++++++++++++++--------- 6 files changed, 68 insertions(+), 15 deletions(-) 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 @@ -290,6 +290,14 @@ self.assertTrue(b.startswith(b"h")) self.assertFalse(b.startswith(b"hellow")) self.assertFalse(b.startswith(b"ha")) + try: + b.startswith([b'h']) + except TypeError as err: + exc = str(err) + else: + self.fail('startswith unexpectedly succeeded') + self.assertIn('bytes', exc) + self.assertIn('tuple', exc) def test_endswith(self): b = self.type2test(b'hello') @@ -299,6 +307,14 @@ self.assertTrue(b.endswith(b"o")) self.assertFalse(b.endswith(b"whello")) self.assertFalse(b.endswith(b"no")) + try: + b.endswith([b'o']) + except TypeError as err: + exc = str(err) + else: + self.fail('endswith unexpectedly succeeded') + self.assertIn('bytes', exc) + self.assertIn('tuple', exc) def test_find(self): b = self.type2test(b'mississippi') 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 @@ -789,6 +789,17 @@ self.assertEqual('%f' % INF, 'inf') self.assertEqual('%F' % INF, 'INF') + def test_startswith_endswith_errors(self): + for meth in ('foo'.startswith, 'foo'.endswith): + try: + meth(['f']) + except TypeError as err: + exc = str(err) + else: + self.fail('starts/endswith unexpectedly succeeded') + self.assertIn('str', exc) + self.assertIn('tuple', exc) + @support.run_with_locale('LC_ALL', 'de_DE', 'fr_FR') def test_format_float(self): # should not format with a comma, but always with C locale diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #6780: fix starts/endswith error message to mention that tuples are + accepted too. + - Issue #5057: fix a bug in the peepholer that led to non-portable pyc files between narrow and wide builds while optimizing BINARY_SUBSCR on non-BMP chars (e.g. "\U00012345"[0]). diff --git a/Objects/bytearrayobject.c b/Objects/bytearrayobject.c --- a/Objects/bytearrayobject.c +++ b/Objects/bytearrayobject.c @@ -1281,7 +1281,7 @@ Return True if B starts with the specified prefix, False otherwise.\n\ With optional start, test B beginning at that position.\n\ With optional end, stop comparing B at that position.\n\ -prefix can also be a tuple of strings to try."); +prefix can also be a tuple of bytes to try."); static PyObject * bytearray_startswith(PyByteArrayObject *self, PyObject *args) @@ -1308,8 +1308,12 @@ Py_RETURN_FALSE; } result = _bytearray_tailmatch(self, subobj, start, end, -1); - if (result == -1) + if (result == -1) { + if (PyErr_ExceptionMatches(PyExc_TypeError)) + PyErr_Format(PyExc_TypeError, "startswith first arg must be bytes " + "or a tuple of bytes, not %s", Py_TYPE(subobj)->tp_name); return NULL; + } else return PyBool_FromLong(result); } @@ -1320,7 +1324,7 @@ Return True if B ends with the specified suffix, False otherwise.\n\ With optional start, test B beginning at that position.\n\ With optional end, stop comparing B at that position.\n\ -suffix can also be a tuple of strings to try."); +suffix can also be a tuple of bytes to try."); static PyObject * bytearray_endswith(PyByteArrayObject *self, PyObject *args) @@ -1347,8 +1351,12 @@ Py_RETURN_FALSE; } result = _bytearray_tailmatch(self, subobj, start, end, +1); - if (result == -1) + if (result == -1) { + if (PyErr_ExceptionMatches(PyExc_TypeError)) + PyErr_Format(PyExc_TypeError, "endswith first arg must be bytes or " + "a tuple of bytes, not %s", Py_TYPE(subobj)->tp_name); return NULL; + } else return PyBool_FromLong(result); } diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -2654,8 +2654,12 @@ Py_RETURN_FALSE; } result = _bytes_tailmatch(self, subobj, start, end, -1); - if (result == -1) + if (result == -1) { + if (PyErr_ExceptionMatches(PyExc_TypeError)) + PyErr_Format(PyExc_TypeError, "startswith first arg must be bytes " + "or a tuple of bytes, not %s", Py_TYPE(subobj)->tp_name); return NULL; + } else return PyBool_FromLong(result); } @@ -2694,8 +2698,12 @@ Py_RETURN_FALSE; } result = _bytes_tailmatch(self, subobj, start, end, +1); - if (result == -1) + if (result == -1) { + if (PyErr_ExceptionMatches(PyExc_TypeError)) + PyErr_Format(PyExc_TypeError, "endswith first arg must be bytes or " + "a tuple of bytes, not %s", Py_TYPE(subobj)->tp_name); return NULL; + } else return PyBool_FromLong(result); } diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -1554,7 +1554,7 @@ arg = PyUnicode_FromObject(arg); if (!arg) return 0; - output = PyUnicode_AsEncodedObject(arg, + output = PyUnicode_AsEncodedObject(arg, Py_FileSystemDefaultEncoding, "surrogateescape"); Py_DECREF(arg); @@ -1569,7 +1569,7 @@ if (PyBytes_Check(output)) { size = PyBytes_GET_SIZE(output); data = PyBytes_AS_STRING(output); - } + } else { size = PyByteArray_GET_SIZE(output); data = PyByteArray_AS_STRING(output); @@ -2148,7 +2148,7 @@ illegal prefix. See RFC 3629 for details */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 00-0F */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -2631,7 +2631,7 @@ #endif PyObject *errorHandler = NULL; PyObject *exc = NULL; - + q = (unsigned char *)s; e = q + size; @@ -8743,8 +8743,12 @@ Py_RETURN_FALSE; } substring = (PyUnicodeObject *)PyUnicode_FromObject(subobj); - if (substring == NULL) - return NULL; + if (substring == NULL) { + if (PyErr_ExceptionMatches(PyExc_TypeError)) + PyErr_Format(PyExc_TypeError, "startswith first arg must be str or " + "a tuple of str, not %s", Py_TYPE(subobj)->tp_name); + return NULL; + } result = tailmatch(self, substring, start, end, -1); Py_DECREF(substring); return PyBool_FromLong(result); @@ -8787,9 +8791,12 @@ Py_RETURN_FALSE; } substring = (PyUnicodeObject *)PyUnicode_FromObject(subobj); - if (substring == NULL) - return NULL; - + if (substring == NULL) { + if (PyErr_ExceptionMatches(PyExc_TypeError)) + PyErr_Format(PyExc_TypeError, "endswith first arg must be str or " + "a tuple of str, not %s", Py_TYPE(subobj)->tp_name); + return NULL; + } result = tailmatch(self, substring, start, end, +1); Py_DECREF(substring); return PyBool_FromLong(result); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 26 05:45:25 2011 From: python-checkins at python.org (ezio.melotti) Date: Tue, 26 Apr 2011 05:45:25 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): #6780: merge with 3.1. Message-ID: http://hg.python.org/cpython/rev/f393c507717a changeset: 69564:f393c507717a branch: 3.2 parent: 69560:cca4c92bf337 parent: 69563:bcbf8c3c4a88 user: Ezio Melotti date: Tue Apr 26 06:40:59 2011 +0300 summary: #6780: merge with 3.1. files: Lib/test/test_bytes.py | 10 ++++++++++ Lib/test/test_unicode.py | 8 ++++++++ Misc/NEWS | 3 +++ Objects/bytearrayobject.c | 16 ++++++++++++---- Objects/bytesobject.c | 12 ++++++++++-- Objects/unicodeobject.c | 17 ++++++++++++----- 6 files changed, 55 insertions(+), 11 deletions(-) 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 @@ -303,6 +303,11 @@ self.assertTrue(b.startswith(b"h")) self.assertFalse(b.startswith(b"hellow")) self.assertFalse(b.startswith(b"ha")) + with self.assertRaises(TypeError) as cm: + b.startswith([b'h']) + exc = str(cm.exception) + self.assertIn('bytes', exc) + self.assertIn('tuple', exc) def test_endswith(self): b = self.type2test(b'hello') @@ -312,6 +317,11 @@ self.assertTrue(b.endswith(b"o")) self.assertFalse(b.endswith(b"whello")) self.assertFalse(b.endswith(b"no")) + with self.assertRaises(TypeError) as cm: + b.endswith([b'o']) + exc = str(cm.exception) + self.assertIn('bytes', exc) + self.assertIn('tuple', exc) def test_find(self): b = self.type2test(b'mississippi') 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 @@ -819,6 +819,14 @@ self.assertEqual('%f' % INF, 'inf') self.assertEqual('%F' % INF, 'INF') + def test_startswith_endswith_errors(self): + for meth in ('foo'.startswith, 'foo'.endswith): + with self.assertRaises(TypeError) as cm: + meth(['f']) + exc = str(cm.exception) + self.assertIn('str', exc) + self.assertIn('tuple', exc) + @support.run_with_locale('LC_ALL', 'de_DE', 'fr_FR') def test_format_float(self): # should not format with a comma, but always with C locale diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #6780: fix starts/endswith error message to mention that tuples are + accepted too. + - Issue #5057: fix a bug in the peepholer that led to non-portable pyc files between narrow and wide builds while optimizing BINARY_SUBSCR on non-BMP chars (e.g. "\U00012345"[0]). diff --git a/Objects/bytearrayobject.c b/Objects/bytearrayobject.c --- a/Objects/bytearrayobject.c +++ b/Objects/bytearrayobject.c @@ -1280,7 +1280,7 @@ Return True if B starts with the specified prefix, False otherwise.\n\ With optional start, test B beginning at that position.\n\ With optional end, stop comparing B at that position.\n\ -prefix can also be a tuple of strings to try."); +prefix can also be a tuple of bytes to try."); static PyObject * bytearray_startswith(PyByteArrayObject *self, PyObject *args) @@ -1307,8 +1307,12 @@ Py_RETURN_FALSE; } result = _bytearray_tailmatch(self, subobj, start, end, -1); - if (result == -1) + if (result == -1) { + if (PyErr_ExceptionMatches(PyExc_TypeError)) + PyErr_Format(PyExc_TypeError, "startswith first arg must be bytes " + "or a tuple of bytes, not %s", Py_TYPE(subobj)->tp_name); return NULL; + } else return PyBool_FromLong(result); } @@ -1319,7 +1323,7 @@ Return True if B ends with the specified suffix, False otherwise.\n\ With optional start, test B beginning at that position.\n\ With optional end, stop comparing B at that position.\n\ -suffix can also be a tuple of strings to try."); +suffix can also be a tuple of bytes to try."); static PyObject * bytearray_endswith(PyByteArrayObject *self, PyObject *args) @@ -1346,8 +1350,12 @@ Py_RETURN_FALSE; } result = _bytearray_tailmatch(self, subobj, start, end, +1); - if (result == -1) + if (result == -1) { + if (PyErr_ExceptionMatches(PyExc_TypeError)) + PyErr_Format(PyExc_TypeError, "endswith first arg must be bytes or " + "a tuple of bytes, not %s", Py_TYPE(subobj)->tp_name); return NULL; + } else return PyBool_FromLong(result); } diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -2228,8 +2228,12 @@ Py_RETURN_FALSE; } result = _bytes_tailmatch(self, subobj, start, end, -1); - if (result == -1) + if (result == -1) { + if (PyErr_ExceptionMatches(PyExc_TypeError)) + PyErr_Format(PyExc_TypeError, "startswith first arg must be bytes " + "or a tuple of bytes, not %s", Py_TYPE(subobj)->tp_name); return NULL; + } else return PyBool_FromLong(result); } @@ -2268,8 +2272,12 @@ Py_RETURN_FALSE; } result = _bytes_tailmatch(self, subobj, start, end, +1); - if (result == -1) + if (result == -1) { + if (PyErr_ExceptionMatches(PyExc_TypeError)) + PyErr_Format(PyExc_TypeError, "endswith first arg must be bytes or " + "a tuple of bytes, not %s", Py_TYPE(subobj)->tp_name); return NULL; + } else return PyBool_FromLong(result); } diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -9029,8 +9029,12 @@ Py_RETURN_FALSE; } substring = (PyUnicodeObject *)PyUnicode_FromObject(subobj); - if (substring == NULL) - return NULL; + if (substring == NULL) { + if (PyErr_ExceptionMatches(PyExc_TypeError)) + PyErr_Format(PyExc_TypeError, "startswith first arg must be str or " + "a tuple of str, not %s", Py_TYPE(subobj)->tp_name); + return NULL; + } result = tailmatch(self, substring, start, end, -1); Py_DECREF(substring); return PyBool_FromLong(result); @@ -9073,9 +9077,12 @@ Py_RETURN_FALSE; } substring = (PyUnicodeObject *)PyUnicode_FromObject(subobj); - if (substring == NULL) - return NULL; - + if (substring == NULL) { + if (PyErr_ExceptionMatches(PyExc_TypeError)) + PyErr_Format(PyExc_TypeError, "endswith first arg must be str or " + "a tuple of str, not %s", Py_TYPE(subobj)->tp_name); + return NULL; + } result = tailmatch(self, substring, start, end, +1); Py_DECREF(substring); return PyBool_FromLong(result); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 26 05:45:26 2011 From: python-checkins at python.org (ezio.melotti) Date: Tue, 26 Apr 2011 05:45:26 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): #6780: merge with 3.2. Message-ID: http://hg.python.org/cpython/rev/a1a1296556d7 changeset: 69565:a1a1296556d7 parent: 69561:07149918bce1 parent: 69564:f393c507717a user: Ezio Melotti date: Tue Apr 26 06:45:24 2011 +0300 summary: #6780: merge with 3.2. files: Lib/test/test_bytes.py | 10 ++++++++++ Lib/test/test_unicode.py | 8 ++++++++ Misc/NEWS | 3 +++ Objects/bytearrayobject.c | 16 ++++++++++++---- Objects/bytesobject.c | 12 ++++++++++-- Objects/unicodeobject.c | 17 ++++++++++++----- 6 files changed, 55 insertions(+), 11 deletions(-) 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 @@ -305,6 +305,11 @@ self.assertTrue(b.startswith(b"h")) self.assertFalse(b.startswith(b"hellow")) self.assertFalse(b.startswith(b"ha")) + with self.assertRaises(TypeError) as cm: + b.startswith([b'h']) + exc = str(cm.exception) + self.assertIn('bytes', exc) + self.assertIn('tuple', exc) def test_endswith(self): b = self.type2test(b'hello') @@ -314,6 +319,11 @@ self.assertTrue(b.endswith(b"o")) self.assertFalse(b.endswith(b"whello")) self.assertFalse(b.endswith(b"no")) + with self.assertRaises(TypeError) as cm: + b.endswith([b'o']) + exc = str(cm.exception) + self.assertIn('bytes', exc) + self.assertIn('tuple', exc) def test_find(self): b = self.type2test(b'mississippi') 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 @@ -819,6 +819,14 @@ self.assertEqual('%f' % INF, 'inf') self.assertEqual('%F' % INF, 'INF') + def test_startswith_endswith_errors(self): + for meth in ('foo'.startswith, 'foo'.endswith): + with self.assertRaises(TypeError) as cm: + meth(['f']) + exc = str(cm.exception) + self.assertIn('str', exc) + self.assertIn('tuple', exc) + @support.run_with_locale('LC_ALL', 'de_DE', 'fr_FR') def test_format_float(self): # should not format with a comma, but always with C locale diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #6780: fix starts/endswith error message to mention that tuples are + accepted too. + - Issue #5057: fix a bug in the peepholer that led to non-portable pyc files between narrow and wide builds while optimizing BINARY_SUBSCR on non-BMP chars (e.g. "\U00012345"[0]). diff --git a/Objects/bytearrayobject.c b/Objects/bytearrayobject.c --- a/Objects/bytearrayobject.c +++ b/Objects/bytearrayobject.c @@ -1304,7 +1304,7 @@ Return True if B starts with the specified prefix, False otherwise.\n\ With optional start, test B beginning at that position.\n\ With optional end, stop comparing B at that position.\n\ -prefix can also be a tuple of strings to try."); +prefix can also be a tuple of bytes to try."); static PyObject * bytearray_startswith(PyByteArrayObject *self, PyObject *args) @@ -1331,8 +1331,12 @@ Py_RETURN_FALSE; } result = _bytearray_tailmatch(self, subobj, start, end, -1); - if (result == -1) + if (result == -1) { + if (PyErr_ExceptionMatches(PyExc_TypeError)) + PyErr_Format(PyExc_TypeError, "startswith first arg must be bytes " + "or a tuple of bytes, not %s", Py_TYPE(subobj)->tp_name); return NULL; + } else return PyBool_FromLong(result); } @@ -1343,7 +1347,7 @@ Return True if B ends with the specified suffix, False otherwise.\n\ With optional start, test B beginning at that position.\n\ With optional end, stop comparing B at that position.\n\ -suffix can also be a tuple of strings to try."); +suffix can also be a tuple of bytes to try."); static PyObject * bytearray_endswith(PyByteArrayObject *self, PyObject *args) @@ -1370,8 +1374,12 @@ Py_RETURN_FALSE; } result = _bytearray_tailmatch(self, subobj, start, end, +1); - if (result == -1) + if (result == -1) { + if (PyErr_ExceptionMatches(PyExc_TypeError)) + PyErr_Format(PyExc_TypeError, "endswith first arg must be bytes or " + "a tuple of bytes, not %s", Py_TYPE(subobj)->tp_name); return NULL; + } else return PyBool_FromLong(result); } diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -2224,8 +2224,12 @@ Py_RETURN_FALSE; } result = _bytes_tailmatch(self, subobj, start, end, -1); - if (result == -1) + if (result == -1) { + if (PyErr_ExceptionMatches(PyExc_TypeError)) + PyErr_Format(PyExc_TypeError, "startswith first arg must be bytes " + "or a tuple of bytes, not %s", Py_TYPE(subobj)->tp_name); return NULL; + } else return PyBool_FromLong(result); } @@ -2264,8 +2268,12 @@ Py_RETURN_FALSE; } result = _bytes_tailmatch(self, subobj, start, end, +1); - if (result == -1) + if (result == -1) { + if (PyErr_ExceptionMatches(PyExc_TypeError)) + PyErr_Format(PyExc_TypeError, "endswith first arg must be bytes or " + "a tuple of bytes, not %s", Py_TYPE(subobj)->tp_name); return NULL; + } else return PyBool_FromLong(result); } diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -9101,8 +9101,12 @@ Py_RETURN_FALSE; } substring = (PyUnicodeObject *)PyUnicode_FromObject(subobj); - if (substring == NULL) - return NULL; + if (substring == NULL) { + if (PyErr_ExceptionMatches(PyExc_TypeError)) + PyErr_Format(PyExc_TypeError, "startswith first arg must be str or " + "a tuple of str, not %s", Py_TYPE(subobj)->tp_name); + return NULL; + } result = tailmatch(self, substring, start, end, -1); Py_DECREF(substring); return PyBool_FromLong(result); @@ -9145,9 +9149,12 @@ Py_RETURN_FALSE; } substring = (PyUnicodeObject *)PyUnicode_FromObject(subobj); - if (substring == NULL) - return NULL; - + if (substring == NULL) { + if (PyErr_ExceptionMatches(PyExc_TypeError)) + PyErr_Format(PyExc_TypeError, "endswith first arg must be str or " + "a tuple of str, not %s", Py_TYPE(subobj)->tp_name); + return NULL; + } result = tailmatch(self, substring, start, end, +1); Py_DECREF(substring); return PyBool_FromLong(result); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 26 15:01:25 2011 From: python-checkins at python.org (senthil.kumaran) Date: Tue, 26 Apr 2011 15:01:25 +0200 Subject: [Python-checkins] cpython (3.1): Fix for issue11236 getpass.getpass to respond ctrl-c or ctrl-z Message-ID: http://hg.python.org/cpython/rev/154b323e0e7f changeset: 69566:154b323e0e7f branch: 3.1 parent: 69563:bcbf8c3c4a88 user: Senthil Kumaran date: Tue Apr 26 20:59:46 2011 +0800 summary: Fix for issue11236 getpass.getpass to respond ctrl-c or ctrl-z files: Lib/getpass.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/getpass.py b/Lib/getpass.py --- a/Lib/getpass.py +++ b/Lib/getpass.py @@ -62,7 +62,7 @@ try: old = termios.tcgetattr(fd) # a copy to save new = old[:] - new[3] &= ~(termios.ECHO|termios.ISIG) # 3 == 'lflags' + new[3] &= ~termios.ECHO # 3 == 'lflags' tcsetattr_flags = termios.TCSAFLUSH if hasattr(termios, 'TCSASOFT'): tcsetattr_flags |= termios.TCSASOFT -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 26 15:01:26 2011 From: python-checkins at python.org (senthil.kumaran) Date: Tue, 26 Apr 2011 15:01:26 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): merge from 3.1 codeline. Message-ID: http://hg.python.org/cpython/rev/cca6dc29a900 changeset: 69567:cca6dc29a900 branch: 3.2 parent: 69564:f393c507717a parent: 69566:154b323e0e7f user: Senthil Kumaran date: Tue Apr 26 21:00:27 2011 +0800 summary: merge from 3.1 codeline. files: Lib/getpass.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/getpass.py b/Lib/getpass.py --- a/Lib/getpass.py +++ b/Lib/getpass.py @@ -62,7 +62,7 @@ try: old = termios.tcgetattr(fd) # a copy to save new = old[:] - new[3] &= ~(termios.ECHO|termios.ISIG) # 3 == 'lflags' + new[3] &= ~termios.ECHO # 3 == 'lflags' tcsetattr_flags = termios.TCSAFLUSH if hasattr(termios, 'TCSASOFT'): tcsetattr_flags |= termios.TCSASOFT -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 26 15:03:07 2011 From: python-checkins at python.org (senthil.kumaran) Date: Tue, 26 Apr 2011 15:03:07 +0200 Subject: [Python-checkins] cpython (2.7): issue11236 getpass.getpass to respond ctrl-c or ctrl-z Message-ID: http://hg.python.org/cpython/rev/a3b4887edba4 changeset: 69568:a3b4887edba4 branch: 2.7 parent: 69562:3ceeccbc2c3b user: Senthil Kumaran date: Tue Apr 26 21:02:26 2011 +0800 summary: issue11236 getpass.getpass to respond ctrl-c or ctrl-z files: Lib/getpass.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/getpass.py b/Lib/getpass.py --- a/Lib/getpass.py +++ b/Lib/getpass.py @@ -62,7 +62,7 @@ try: old = termios.tcgetattr(fd) # a copy to save new = old[:] - new[3] &= ~(termios.ECHO|termios.ISIG) # 3 == 'lflags' + new[3] &= ~termios.ECHO # 3 == 'lflags' tcsetattr_flags = termios.TCSAFLUSH if hasattr(termios, 'TCSASOFT'): tcsetattr_flags |= termios.TCSASOFT -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 26 15:14:44 2011 From: python-checkins at python.org (senthil.kumaran) Date: Tue, 26 Apr 2011 15:14:44 +0200 Subject: [Python-checkins] cpython (3.1): Update News entry for Issue11236 Message-ID: http://hg.python.org/cpython/rev/f799530dbde7 changeset: 69569:f799530dbde7 branch: 3.1 parent: 69566:154b323e0e7f user: Senthil Kumaran date: Tue Apr 26 21:09:49 2011 +0800 summary: Update News entry for Issue11236 files: Misc/NEWS | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -61,6 +61,8 @@ Library ------- +- Issue #11236: getpass.getpass responds to ctrl-c or ctrl-z on terminal. + - Issue #11768: The signal handler of the signal module only calls Py_AddPendingCall() for the first signal to fix a deadlock on reentrant or parallel calls. PyErr_SetInterrupt() writes also into the wake up file. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 26 15:14:47 2011 From: python-checkins at python.org (senthil.kumaran) Date: Tue, 26 Apr 2011 15:14:47 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): merge from 3.1 Message-ID: http://hg.python.org/cpython/rev/df4464da7df6 changeset: 69570:df4464da7df6 branch: 3.2 parent: 69567:cca6dc29a900 parent: 69569:f799530dbde7 user: Senthil Kumaran date: Tue Apr 26 21:10:23 2011 +0800 summary: merge from 3.1 files: Misc/NEWS | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -66,6 +66,8 @@ Library ------- +- Issue #11236: getpass.getpass responds to ctrl-c or ctrl-z on terminal. + - Issue #11768: The signal handler of the signal module only calls Py_AddPendingCall() for the first signal to fix a deadlock on reentrant or parallel calls. PyErr_SetInterrupt() writes also into the wake up file. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 26 15:14:49 2011 From: python-checkins at python.org (senthil.kumaran) Date: Tue, 26 Apr 2011 15:14:49 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> default): merge from 2.7 Message-ID: http://hg.python.org/cpython/rev/721efb72dce9 changeset: 69571:721efb72dce9 parent: 69565:a1a1296556d7 parent: 69566:154b323e0e7f user: Senthil Kumaran date: Tue Apr 26 21:12:48 2011 +0800 summary: merge from 2.7 files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 26 15:14:51 2011 From: python-checkins at python.org (senthil.kumaran) Date: Tue, 26 Apr 2011 15:14:51 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): merge from 3.2 Message-ID: http://hg.python.org/cpython/rev/ad7fe87736f0 changeset: 69572:ad7fe87736f0 parent: 69571:721efb72dce9 parent: 69570:df4464da7df6 user: Senthil Kumaran date: Tue Apr 26 21:14:26 2011 +0800 summary: merge from 3.2 files: Misc/NEWS | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -116,6 +116,8 @@ Library ------- +- Issue #11236: getpass.getpass responds to ctrl-c or ctrl-z on terminal. + - Issue #11856: Speed up parsing of JSON numbers. - Issue #11005: threading.RLock()._release_save() raises a RuntimeError if the -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 26 15:18:33 2011 From: python-checkins at python.org (senthil.kumaran) Date: Tue, 26 Apr 2011 15:18:33 +0200 Subject: [Python-checkins] cpython (2.7): Update NEWS for Issue11236. Message-ID: http://hg.python.org/cpython/rev/1b261f3bef09 changeset: 69573:1b261f3bef09 branch: 2.7 parent: 69568:a3b4887edba4 user: Senthil Kumaran date: Tue Apr 26 21:17:45 2011 +0800 summary: Update NEWS for Issue11236. files: Misc/NEWS | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -61,6 +61,8 @@ Library ------- +- Issue #11236: getpass.getpass responds to ctrl-c or ctrl-z on terminal. + - Issue #11768: The signal handler of the signal module only calls Py_AddPendingCall() for the first signal to fix a deadlock on reentrant or parallel calls. PyErr_SetInterrupt() writes also into the wake up file. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 26 18:53:48 2011 From: python-checkins at python.org (antoine.pitrou) Date: Tue, 26 Apr 2011 18:53:48 +0200 Subject: [Python-checkins] cpython: I think this should be "versionchanged", not "versionadded" Message-ID: http://hg.python.org/cpython/rev/b7af4816c70a changeset: 69574:b7af4816c70a parent: 69572:ad7fe87736f0 user: Antoine Pitrou date: Tue Apr 26 18:53:42 2011 +0200 summary: I think this should be "versionchanged", not "versionadded" files: Doc/library/smtplib.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/smtplib.rst b/Doc/library/smtplib.rst --- a/Doc/library/smtplib.rst +++ b/Doc/library/smtplib.rst @@ -45,7 +45,7 @@ (250, b'Ok') >>> - .. versionadded:: 3.3 + .. versionchanged:: 3.3 Support for the :keyword:`with` statement was added. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 26 19:43:12 2011 From: python-checkins at python.org (vinay.sajip) Date: Tue, 26 Apr 2011 19:43:12 +0200 Subject: [Python-checkins] cpython: test_logging coverage improvements. Message-ID: http://hg.python.org/cpython/rev/ababe8a73327 changeset: 69575:ababe8a73327 user: Vinay Sajip date: Tue Apr 26 18:43:05 2011 +0100 summary: test_logging coverage improvements. files: Lib/logging/__init__.py | 56 ++++++------ Lib/test/test_logging.py | 113 +++++++++++++++++++++++++- 2 files changed, 136 insertions(+), 33 deletions(-) diff --git a/Lib/logging/__init__.py b/Lib/logging/__init__.py --- a/Lib/logging/__init__.py +++ b/Lib/logging/__init__.py @@ -37,13 +37,13 @@ try: import codecs -except ImportError: +except ImportError: #pragma: no cover codecs = None try: import _thread as thread import threading -except ImportError: +except ImportError: #pragma: no cover thread = None __author__ = "Vinay Sajip " @@ -67,16 +67,16 @@ _srcfile = __file__ _srcfile = os.path.normcase(_srcfile) -# next bit filched from 1.5.2's inspect.py -def currentframe(): - """Return the frame object for the caller's stack frame.""" - try: - raise Exception - except: - return sys.exc_info()[2].tb_frame.f_back -if hasattr(sys, '_getframe'): currentframe = lambda: sys._getframe(3) -# done filching +if hasattr(sys, '_getframe'): + currentframe = lambda: sys._getframe(3) +else: #pragma: no cover + def currentframe(): + """Return the frame object for the caller's stack frame.""" + try: + raise Exception + except: + return sys.exc_info()[2].tb_frame.f_back # _srcfile is only used in conjunction with sys._getframe(). # To provide compatibility with older versions of Python, set _srcfile @@ -94,22 +94,22 @@ #raiseExceptions is used to see if exceptions during handling should be #propagated # -raiseExceptions = 1 +raiseExceptions = True # # If you don't want threading information in the log, set this to zero # -logThreads = 1 +logThreads = True # # If you don't want multiprocessing information in the log, set this to zero # -logMultiprocessing = 1 +logMultiprocessing = True # # If you don't want process information in the log, set this to zero # -logProcesses = 1 +logProcesses = True #--------------------------------------------------------------------------- # Level related stuff @@ -201,7 +201,7 @@ # if thread: _lock = threading.RLock() -else: +else: #pragma: no cover _lock = None @@ -281,10 +281,10 @@ if logThreads and thread: self.thread = thread.get_ident() self.threadName = threading.current_thread().name - else: + else: # pragma: no cover self.thread = None self.threadName = None - if not logMultiprocessing: + if not logMultiprocessing: # pragma: no cover self.processName = None else: self.processName = 'MainProcess' @@ -644,11 +644,11 @@ yes. If deemed appropriate, the record may be modified in-place. """ if self.nlen == 0: - return 1 + return True elif self.name == record.name: - return 1 + return True elif record.name.find(self.name, 0, self.nlen) != 0: - return 0 + return False return (record.name[self.nlen] == ".") class Filterer(object): @@ -775,7 +775,7 @@ """ if thread: self.lock = threading.RLock() - else: + else: #pragma: no cover self.lock = None def acquire(self): @@ -939,7 +939,7 @@ stream.write(msg) stream.write(self.terminator) self.flush() - except (KeyboardInterrupt, SystemExit): + except (KeyboardInterrupt, SystemExit): #pragma: no cover raise except: self.handleError(record) @@ -948,13 +948,13 @@ """ A handler class which writes formatted logging records to disk files. """ - def __init__(self, filename, mode='a', encoding=None, delay=0): + def __init__(self, filename, mode='a', encoding=None, delay=False): """ Open the specified file and use it as the stream for logging. """ #keep the absolute path, otherwise derived classes which use this #may come a cropper when the current directory changes - if codecs is None: + if codecs is None: #pragma: no cover encoding = None self.baseFilename = os.path.abspath(filename) self.mode = mode @@ -1352,9 +1352,9 @@ #IronPython can use logging. try: fn, lno, func, sinfo = self.findCaller(stack_info) - except ValueError: + except ValueError: # pragma: no cover fn, lno, func = "(unknown file)", 0, "(unknown function)" - else: + else: # pragma: no cover fn, lno, func = "(unknown file)", 0, "(unknown function)" if exc_info: if not isinstance(exc_info, tuple): @@ -1465,7 +1465,7 @@ Is this logger enabled for level 'level'? """ if self.manager.disable >= level: - return 0 + return False return level >= self.getEffectiveLevel() def getChild(self, suffix): 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 @@ -494,6 +494,37 @@ handler.removeFilter(garr) +class HandlerTest(BaseTest): + def test_name(self): + h = logging.Handler() + h.name = 'generic' + self.assertEqual(h.name, 'generic') + h.name = 'anothergeneric' + self.assertEqual(h.name, 'anothergeneric') + self.assertRaises(NotImplementedError, h.emit, None) + + def test_abc(self): + pass + +class BadStream(object): + def write(self, data): + raise RuntimeError('deliberate mistake') + +class TestStreamHandler(logging.StreamHandler): + def handleError(self, record): + self.error_record = record + +class StreamHandlerTest(BaseTest): + def test_error_handling(self): + h = TestStreamHandler(BadStream()) + r = logging.makeLogRecord({}) + old_raise = logging.raiseExceptions + try: + h.handle(r) + self.assertIs(h.error_record, r) + finally: + logging.raiseExceptions = old_raise + class MemoryHandlerTest(BaseTest): """Tests for the MemoryHandler.""" @@ -2196,6 +2227,39 @@ f = logging.Formatter('asctime', style='$') self.assertFalse(f.usesTime()) + def test_invalid_style(self): + self.assertRaises(ValueError, logging.Formatter, None, None, 'x') + + def test_time(self): + r = self.get_record() + r.created = 735375780.0 # 21 April 1993 08:03:00 + r.msecs = 123 + f = logging.Formatter('%(asctime)s %(message)s') + self.assertEqual(f.formatTime(r), '1993-04-21 08:03:00,123') + self.assertEqual(f.formatTime(r, '%Y:%d'), '1993:21') + +class ExceptionTest(BaseTest): + def test_formatting(self): + r = self.root_logger + h = RecordingHandler() + r.addHandler(h) + try: + raise RuntimeError('deliberate mistake') + except: + logging.exception('failed', stack_info=True) + r.removeHandler(h) + h.close() + r = h.records[0] + self.assertTrue(r.exc_text.startswith('Traceback (most recent ' + 'call last):\n')) + self.assertTrue(r.exc_text.endswith('\nRuntimeError: ' + 'deliberate mistake')) + self.assertTrue(r.stack_info.startswith('Stack (most recent ' + 'call last):\n')) + self.assertTrue(r.stack_info.endswith('logging.exception(\'failed\', ' + 'stack_info=True)')) + + class LastResortTest(BaseTest): def test_last_resort(self): # Test the last resort handler @@ -2407,6 +2471,23 @@ logging.setLoggerClass(logging.Logger) self.assertEqual(logging.getLoggerClass(), logging.Logger) +class LogRecordTest(BaseTest): + def test_str_rep(self): + r = logging.makeLogRecord({}) + s = str(r) + self.assertTrue(s.startswith('')) + + def test_dict_arg(self): + h = RecordingHandler() + r = logging.getLogger() + r.addHandler(h) + d = {'less' : 'more' } + logging.warning('less is %(less)s', d) + self.assertIs(h.records[0].args, d) + self.assertEqual(h.records[0].message, 'less is more') + r.removeHandler(h) + h.close() class BasicConfigTest(unittest.TestCase): @@ -2508,6 +2589,9 @@ logging.basicConfig(level=57) self.assertEqual(logging.root.level, 57) + # Test that second call has no effect + logging.basicConfig(level=58) + self.assertEqual(logging.root.level, 57) def test_incompatible(self): assertRaises = self.assertRaises @@ -2521,12 +2605,20 @@ handlers=handlers) def test_handlers(self): - handlers = [logging.StreamHandler(), logging.StreamHandler(sys.stdout)] + handlers = [ + logging.StreamHandler(), + logging.StreamHandler(sys.stdout), + logging.StreamHandler(), + ] + f = logging.Formatter() + handlers[2].setFormatter(f) logging.basicConfig(handlers=handlers) self.assertIs(handlers[0], logging.root.handlers[0]) self.assertIs(handlers[1], logging.root.handlers[1]) + self.assertIs(handlers[2], logging.root.handlers[2]) self.assertIsNotNone(handlers[0].formatter) self.assertIsNotNone(handlers[1].formatter) + self.assertIs(handlers[2].formatter, f) self.assertIs(handlers[0].formatter, handlers[1].formatter) def _test_log(self, method, level=None): @@ -2758,6 +2850,17 @@ self.rmfiles.append(filename) +class FileHandlerTest(BaseFileTest): + def test_delay(self): + os.unlink(self.fn) + fh = logging.FileHandler(self.fn, delay=True) + self.assertIsNone(fh.stream) + self.assertFalse(os.path.exists(self.fn)) + fh.handle(logging.makeLogRecord({})) + self.assertIsNotNone(fh.stream) + self.assertTrue(os.path.exists(self.fn)) + fh.close() + class RotatingFileHandlerTest(BaseFileTest): def next_rec(self): return logging.LogRecord('n', logging.DEBUG, 'p', 1, @@ -2851,15 +2954,15 @@ @run_with_locale('LC_ALL', '') def test_main(): run_unittest(BuiltinLevelsTest, BasicFilterTest, - CustomLevelsAndFiltersTest, MemoryHandlerTest, + CustomLevelsAndFiltersTest, HandlerTest, MemoryHandlerTest, ConfigFileTest, SocketHandlerTest, MemoryTest, EncodingTest, WarningsTest, ConfigDictTest, ManagerTest, - FormatterTest, + FormatterTest, StreamHandlerTest, LogRecordFactoryTest, ChildLoggerTest, QueueHandlerTest, ShutdownTest, ModuleLevelMiscTest, BasicConfigTest, LoggerAdapterTest, LoggerTest, - RotatingFileHandlerTest, - LastResortTest, + FileHandlerTest, RotatingFileHandlerTest, + LastResortTest, LogRecordTest, ExceptionTest, TimedRotatingFileHandlerTest ) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 26 20:34:11 2011 From: python-checkins at python.org (vinay.sajip) Date: Tue, 26 Apr 2011 20:34:11 +0200 Subject: [Python-checkins] cpython: More test_logging coverage improvements. Message-ID: http://hg.python.org/cpython/rev/6a86a2b2f3db changeset: 69576:6a86a2b2f3db user: Vinay Sajip date: Tue Apr 26 19:34:04 2011 +0100 summary: More test_logging coverage improvements. files: Lib/logging/__init__.py | 2 +- Lib/logging/config.py | 6 +- Lib/logging/handlers.py | 18 +++++----- Lib/test/test_logging.py | 45 +++++++++++++++++++++++++++- 4 files changed, 57 insertions(+), 14 deletions(-) diff --git a/Lib/logging/__init__.py b/Lib/logging/__init__.py --- a/Lib/logging/__init__.py +++ b/Lib/logging/__init__.py @@ -890,7 +890,7 @@ None, sys.stderr) sys.stderr.write('Logged from file %s, line %s\n' % ( record.filename, record.lineno)) - except IOError: + except IOError: #pragma: no cover pass # see issue 5971 finally: del ei diff --git a/Lib/logging/config.py b/Lib/logging/config.py --- a/Lib/logging/config.py +++ b/Lib/logging/config.py @@ -30,7 +30,7 @@ try: import _thread as thread import threading -except ImportError: +except ImportError: #pragma: no cover thread = None from socketserver import ThreadingTCPServer, StreamRequestHandler @@ -786,7 +786,7 @@ and which you can join() when appropriate. To stop the server, call stopListening(). """ - if not thread: + if not thread: #pragma: no cover raise NotImplementedError("listen() needs threading to work") class ConfigStreamHandler(StreamRequestHandler): @@ -825,7 +825,7 @@ file = io.StringIO(chunk) try: fileConfig(file) - except (KeyboardInterrupt, SystemExit): + except (KeyboardInterrupt, SystemExit): #pragma: no cover raise except: traceback.print_exc() diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py --- a/Lib/logging/handlers.py +++ b/Lib/logging/handlers.py @@ -31,7 +31,7 @@ try: import codecs -except ImportError: +except ImportError: #pragma: no cover codecs = None # @@ -57,7 +57,7 @@ """ Use the specified filename for streamed logging """ - if codecs is None: + if codecs is None: #pragma: no cover encoding = None logging.FileHandler.__init__(self, filename, mode, encoding, delay) self.mode = mode @@ -74,7 +74,7 @@ if self.shouldRollover(record): self.doRollover() logging.FileHandler.emit(self, record) - except (KeyboardInterrupt, SystemExit): + except (KeyboardInterrupt, SystemExit): #pragma: no cover raise except: self.handleError(record) @@ -542,7 +542,7 @@ try: s = self.makePickle(record) self.send(s) - except (KeyboardInterrupt, SystemExit): + except (KeyboardInterrupt, SystemExit): #pragma: no cover raise except: self.handleError(record) @@ -794,7 +794,7 @@ self.socket.sendto(msg, self.address) else: self.socket.sendall(msg) - except (KeyboardInterrupt, SystemExit): + except (KeyboardInterrupt, SystemExit): #pragma: no cover raise except: self.handleError(record) @@ -871,7 +871,7 @@ smtp.login(self.username, self.password) smtp.sendmail(self.fromaddr, self.toaddrs, msg) smtp.quit() - except (KeyboardInterrupt, SystemExit): + except (KeyboardInterrupt, SystemExit): #pragma: no cover raise except: self.handleError(record) @@ -958,7 +958,7 @@ type = self.getEventType(record) msg = self.format(record) self._welu.ReportEvent(self.appname, id, cat, type, [msg]) - except (KeyboardInterrupt, SystemExit): + except (KeyboardInterrupt, SystemExit): #pragma: no cover raise except: self.handleError(record) @@ -1043,7 +1043,7 @@ h.putheader('Authorization', s) h.endheaders(data if self.method == "POST" else None) h.getresponse() #can't do anything with the result - except (KeyboardInterrupt, SystemExit): + except (KeyboardInterrupt, SystemExit): #pragma: no cover raise except: self.handleError(record) @@ -1213,7 +1213,7 @@ """ try: self.enqueue(self.prepare(record)) - except (KeyboardInterrupt, SystemExit): + except (KeyboardInterrupt, SystemExit): #pragma: no cover raise except: self.handleError(record) 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 @@ -351,6 +351,10 @@ finally: handler.removeFilter(filterfunc) + def test_empty_filter(self): + f = logging.Filter() + r = logging.makeLogRecord({'name': 'spam.eggs'}) + self.assertTrue(f.filter(r)) # # First, we define our levels. There can be as many as you want - the only @@ -519,11 +523,22 @@ h = TestStreamHandler(BadStream()) r = logging.makeLogRecord({}) old_raise = logging.raiseExceptions + old_stderr = sys.stderr try: h.handle(r) self.assertIs(h.error_record, r) + h = logging.StreamHandler(BadStream()) + sys.stderr = sio = io.StringIO() + h.handle(r) + self.assertTrue('\nRuntimeError: ' + 'deliberate mistake\n' in sio.getvalue()) + logging.raiseExceptions = False + sys.stderr = sio = io.StringIO() + h.handle(r) + self.assertEqual('', sio.getvalue()) finally: logging.raiseExceptions = old_raise + sys.stderr = old_stderr class MemoryHandlerTest(BaseTest): @@ -2237,6 +2252,34 @@ f = logging.Formatter('%(asctime)s %(message)s') self.assertEqual(f.formatTime(r), '1993-04-21 08:03:00,123') self.assertEqual(f.formatTime(r, '%Y:%d'), '1993:21') + f.format(r) + self.assertEqual(r.asctime, '1993-04-21 08:03:00,123') + +class TestBufferingFormatter(logging.BufferingFormatter): + def formatHeader(self, records): + return '[(%d)' % len(records) + + def formatFooter(self, records): + return '(%d)]' % len(records) + +class BufferingFormatterTest(unittest.TestCase): + def setUp(self): + self.records = [ + logging.makeLogRecord({'msg': 'one'}), + logging.makeLogRecord({'msg': 'two'}), + ] + + def test_default(self): + f = logging.BufferingFormatter() + self.assertEqual('', f.format([])) + self.assertEqual('onetwo', f.format(self.records)) + + def test_custom(self): + f = TestBufferingFormatter() + self.assertEqual('[(2)onetwo(2)]', f.format(self.records)) + lf = logging.Formatter('<%(message)s>') + f = TestBufferingFormatter(lf) + self.assertEqual('[(2)(2)]', f.format(self.records)) class ExceptionTest(BaseTest): def test_formatting(self): @@ -2957,7 +3000,7 @@ CustomLevelsAndFiltersTest, HandlerTest, MemoryHandlerTest, ConfigFileTest, SocketHandlerTest, MemoryTest, EncodingTest, WarningsTest, ConfigDictTest, ManagerTest, - FormatterTest, StreamHandlerTest, + FormatterTest, BufferingFormatterTest, StreamHandlerTest, LogRecordFactoryTest, ChildLoggerTest, QueueHandlerTest, ShutdownTest, ModuleLevelMiscTest, BasicConfigTest, LoggerAdapterTest, LoggerTest, -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 26 21:05:32 2011 From: python-checkins at python.org (vinay.sajip) Date: Tue, 26 Apr 2011 21:05:32 +0200 Subject: [Python-checkins] cpython: Yet more test_logging coverage improvements. Message-ID: http://hg.python.org/cpython/rev/edc9de09d276 changeset: 69577:edc9de09d276 user: Vinay Sajip date: Tue Apr 26 20:05:24 2011 +0100 summary: Yet more test_logging coverage improvements. files: Lib/test/test_logging.py | 21 +++++++++++++++++++++ 1 files changed, 21 insertions(+), 0 deletions(-) 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 @@ -2047,6 +2047,27 @@ # Original logger output is empty. self.assert_log_lines([]) + def test_baseconfig(self): + d = { + 'atuple': (1, 2, 3), + 'alist': ['a', 'b', 'c'], + 'adict': {'d': 'e', 'f': 3 }, + 'nest1': ('g', ('h', 'i'), 'j'), + 'nest2': ['k', ['l', 'm'], 'n'], + 'nest3': ['o', 'cfg://alist', 'p'], + } + bc = logging.config.BaseConfigurator(d) + self.assertEqual(bc.convert('cfg://atuple[1]'), 2) + self.assertEqual(bc.convert('cfg://alist[1]'), 'b') + self.assertEqual(bc.convert('cfg://nest1[1][0]'), 'h') + self.assertEqual(bc.convert('cfg://nest2[1][1]'), 'm') + self.assertEqual(bc.convert('cfg://adict.d'), 'e') + self.assertEqual(bc.convert('cfg://adict[f]'), 3) + v = bc.convert('cfg://nest3') + self.assertEqual(v.pop(1), ['a', 'b', 'c']) + self.assertRaises(KeyError, bc.convert, 'cfg://nosuch') + self.assertRaises(ValueError, bc.convert, 'cfg://!') + self.assertRaises(KeyError, bc.convert, 'cfg://adict[2]') class ManagerTest(BaseTest): def test_manager_loggerclass(self): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 26 21:26:48 2011 From: python-checkins at python.org (vinay.sajip) Date: Tue, 26 Apr 2011 21:26:48 +0200 Subject: [Python-checkins] cpython: Refined time test in test_logging. Message-ID: http://hg.python.org/cpython/rev/5185e1d91f3d changeset: 69578:5185e1d91f3d user: Vinay Sajip date: Tue Apr 26 20:26:41 2011 +0100 summary: Refined time test in test_logging. files: Lib/test/test_logging.py | 17 ++++++++++++++++- 1 files changed, 16 insertions(+), 1 deletions(-) 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 @@ -43,6 +43,7 @@ from test.support import captured_stdout, run_with_locale, run_unittest, patch from test.support import TestHandler, Matcher import textwrap +import time import unittest import warnings import weakref @@ -2190,6 +2191,18 @@ self.assertTrue(handler.matches(levelno=logging.ERROR, message='2')) self.assertTrue(handler.matches(levelno=logging.CRITICAL, message='3')) +ZERO = datetime.timedelta(0) + +class UTC(datetime.tzinfo): + def utcoffset(self, dt): + return ZERO + + dst = utcoffset + + def tzname(self, dt): + return 'UTC' + +utc = UTC() class FormatterTest(unittest.TestCase): def setUp(self): @@ -2268,9 +2281,11 @@ def test_time(self): r = self.get_record() - r.created = 735375780.0 # 21 April 1993 08:03:00 + dt = datetime.datetime(1993,4,21,8,3,0,0,utc) + r.created = time.mktime(dt.utctimetuple()) r.msecs = 123 f = logging.Formatter('%(asctime)s %(message)s') + f.converter = time.gmtime self.assertEqual(f.formatTime(r), '1993-04-21 08:03:00,123') self.assertEqual(f.formatTime(r, '%Y:%d'), '1993:21') f.format(r) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 26 21:51:15 2011 From: python-checkins at python.org (vinay.sajip) Date: Tue, 26 Apr 2011 21:51:15 +0200 Subject: [Python-checkins] cpython: Disabled test failing on buildbots. Message-ID: http://hg.python.org/cpython/rev/a3b4aefd2460 changeset: 69579:a3b4aefd2460 user: Vinay Sajip date: Tue Apr 26 20:51:07 2011 +0100 summary: Disabled test failing on buildbots. files: Lib/test/test_logging.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) 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 @@ -2279,7 +2279,7 @@ def test_invalid_style(self): self.assertRaises(ValueError, logging.Formatter, None, None, 'x') - def test_time(self): + def disabled_test_time(self): r = self.get_record() dt = datetime.datetime(1993,4,21,8,3,0,0,utc) r.created = time.mktime(dt.utctimetuple()) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 26 22:48:27 2011 From: python-checkins at python.org (victor.stinner) Date: Tue, 26 Apr 2011 22:48:27 +0200 Subject: [Python-checkins] cpython: Issue #11918: OS/2 and VMS are no more supported because of the lack of Message-ID: http://hg.python.org/cpython/rev/ec754f8d2917 changeset: 69580:ec754f8d2917 user: Victor Stinner date: Tue Apr 26 22:48:24 2011 +0200 summary: Issue #11918: OS/2 and VMS are no more supported because of the lack of maintainer. files: Doc/whatsnew/3.3.rst | 6 ++++++ Misc/NEWS | 3 +++ Modules/main.c | 1 + Modules/posixmodule.c | 2 ++ PC/os2emx/pyconfig.h | 2 ++ 5 files changed, 14 insertions(+), 0 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 @@ -136,6 +136,12 @@ * Stub +Unsupported operating systems +============================= + +OS/2 and VMS are no more supported because of the lack of maintainer. + + Porting to Python 3.3 ===================== diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #11918: OS/2 and VMS are no more supported because of the lack of + maintainer. + - Issue #6780: fix starts/endswith error message to mention that tuples are accepted too. diff --git a/Modules/main.c b/Modules/main.c --- a/Modules/main.c +++ b/Modules/main.c @@ -6,6 +6,7 @@ #include #ifdef __VMS +#error "PEP 11: VMS is now unsupported, code will be removed in Python 3.4" #include #endif diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -30,6 +30,7 @@ #include "Python.h" #if defined(__VMS) +# error "PEP 11: VMS is now unsupported, code will be removed in Python 3.4" # include #endif /* defined(__VMS) */ @@ -45,6 +46,7 @@ #if defined(PYOS_OS2) +#error "PEP 11: OS/2 is now unsupported, code will be removed in Python 3.4" #define INCL_DOS #define INCL_DOSERRORS #define INCL_DOSPROCESS diff --git a/PC/os2emx/pyconfig.h b/PC/os2emx/pyconfig.h --- a/PC/os2emx/pyconfig.h +++ b/PC/os2emx/pyconfig.h @@ -1,6 +1,8 @@ #ifndef Py_CONFIG_H #define Py_CONFIG_H +#error "PEP 11: OS/2 is now unsupported, code will be removed in Python 3.4" + /* config.h. * At some time in the past, generated automatically by/from configure. * now maintained manually. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 26 23:00:14 2011 From: python-checkins at python.org (raymond.hettinger) Date: Tue, 26 Apr 2011 23:00:14 +0200 Subject: [Python-checkins] cpython (3.2): Issue 11929: Minor whitespace clean-ups. Message-ID: http://hg.python.org/cpython/rev/5e93c5cdc378 changeset: 69581:5e93c5cdc378 branch: 3.2 parent: 69570:df4464da7df6 user: Raymond Hettinger date: Tue Apr 26 13:55:55 2011 -0700 summary: Issue 11929: Minor whitespace clean-ups. files: Doc/includes/dbpickle.py | 3 +- Doc/includes/mp_benchmarks.py | 13 ++++++++--- Doc/includes/mp_pool.py | 8 +++--- Doc/includes/mp_synchronize.py | 10 +++++--- Doc/includes/mp_webserver.py | 4 +- Doc/includes/sqlite3/adapter_datetime.py | 3 +- Doc/includes/tzinfo-examples.py | 2 +- 7 files changed, 26 insertions(+), 17 deletions(-) diff --git a/Doc/includes/dbpickle.py b/Doc/includes/dbpickle.py --- a/Doc/includes/dbpickle.py +++ b/Doc/includes/dbpickle.py @@ -47,7 +47,8 @@ def main(): - import io, pprint + import io + import pprint # Initialize and populate our database. conn = sqlite3.connect(":memory:") diff --git a/Doc/includes/mp_benchmarks.py b/Doc/includes/mp_benchmarks.py --- a/Doc/includes/mp_benchmarks.py +++ b/Doc/includes/mp_benchmarks.py @@ -5,7 +5,12 @@ # All rights reserved. # -import time, sys, multiprocessing, threading, queue, gc +import time +import sys +import multiprocessing +import threading +import queue +import gc if sys.platform == 'win32': _timer = time.clock @@ -111,7 +116,7 @@ for i in range(iterations): a = seq[5] - elapsed = _timer()-t + elapsed = _timer() - t print(iterations, 'iterations in', elapsed, 'seconds') print('average number/sec:', iterations/elapsed) @@ -132,7 +137,7 @@ l.acquire() l.release() - elapsed = _timer()-t + elapsed = _timer() - t print(iterations, 'iterations in', elapsed, 'seconds') print('average number/sec:', iterations/elapsed) @@ -169,7 +174,7 @@ c.notify() c.wait() - elapsed = _timer()-t + elapsed = _timer() - t c.release() p.join() diff --git a/Doc/includes/mp_pool.py b/Doc/includes/mp_pool.py --- a/Doc/includes/mp_pool.py +++ b/Doc/includes/mp_pool.py @@ -25,18 +25,18 @@ return calculate(*args) def mul(a, b): - time.sleep(0.5*random.random()) + time.sleep(0.5 * random.random()) return a * b def plus(a, b): - time.sleep(0.5*random.random()) + time.sleep(0.5 * random.random()) return a + b def f(x): - return 1.0 / (x-5.0) + return 1.0 / (x - 5.0) def pow3(x): - return x**3 + return x ** 3 def noop(x): pass diff --git a/Doc/includes/mp_synchronize.py b/Doc/includes/mp_synchronize.py --- a/Doc/includes/mp_synchronize.py +++ b/Doc/includes/mp_synchronize.py @@ -5,7 +5,9 @@ # All rights reserved. # -import time, sys, random +import time +import sys +import random from queue import Empty import multiprocessing # may get overwritten @@ -237,9 +239,9 @@ multiprocessing = namespace - for func in [ test_value, test_queue, test_condition, - test_semaphore, test_join_timeout, test_event, - test_sharedvalues ]: + for func in [test_value, test_queue, test_condition, + test_semaphore, test_join_timeout, test_event, + test_sharedvalues]: print('\n\t######## %s\n' % func.__name__) func() diff --git a/Doc/includes/mp_webserver.py b/Doc/includes/mp_webserver.py --- a/Doc/includes/mp_webserver.py +++ b/Doc/includes/mp_webserver.py @@ -24,7 +24,7 @@ def note(format, *args): - sys.stderr.write('[%s]\t%s\n' % (current_process().name, format%args)) + sys.stderr.write('[%s]\t%s\n' % (current_process().name, format % args)) class RequestHandler(SimpleHTTPRequestHandler): @@ -45,7 +45,7 @@ server = HTTPServer(address, RequestHandler) # create child processes to act as workers - for i in range(number_of_processes-1): + for i in range(number_of_processes - 1): Process(target=serve_forever, args=(server,)).start() # main process also acts as a worker diff --git a/Doc/includes/sqlite3/adapter_datetime.py b/Doc/includes/sqlite3/adapter_datetime.py --- a/Doc/includes/sqlite3/adapter_datetime.py +++ b/Doc/includes/sqlite3/adapter_datetime.py @@ -1,5 +1,6 @@ import sqlite3 -import datetime, time +import datetime +import time def adapt_datetime(ts): return time.mktime(ts.timetuple()) diff --git a/Doc/includes/tzinfo-examples.py b/Doc/includes/tzinfo-examples.py --- a/Doc/includes/tzinfo-examples.py +++ b/Doc/includes/tzinfo-examples.py @@ -27,7 +27,7 @@ """Fixed offset in minutes east from UTC.""" def __init__(self, offset, name): - self.__offset = timedelta(minutes = offset) + self.__offset = timedelta(minutes=offset) self.__name = name def utcoffset(self, dt): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 26 23:00:15 2011 From: python-checkins at python.org (raymond.hettinger) Date: Tue, 26 Apr 2011 23:00:15 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Issue 11929: Minor whitespace clean-ups. Message-ID: http://hg.python.org/cpython/rev/89fcadbc49df changeset: 69582:89fcadbc49df parent: 69579:a3b4aefd2460 parent: 69581:5e93c5cdc378 user: Raymond Hettinger date: Tue Apr 26 13:56:29 2011 -0700 summary: Issue 11929: Minor whitespace clean-ups. files: Doc/includes/dbpickle.py | 3 +- Doc/includes/mp_benchmarks.py | 13 ++++++++--- Doc/includes/mp_pool.py | 8 +++--- Doc/includes/mp_synchronize.py | 10 +++++--- Doc/includes/mp_webserver.py | 4 +- Doc/includes/sqlite3/adapter_datetime.py | 3 +- Doc/includes/tzinfo-examples.py | 2 +- 7 files changed, 26 insertions(+), 17 deletions(-) diff --git a/Doc/includes/dbpickle.py b/Doc/includes/dbpickle.py --- a/Doc/includes/dbpickle.py +++ b/Doc/includes/dbpickle.py @@ -47,7 +47,8 @@ def main(): - import io, pprint + import io + import pprint # Initialize and populate our database. conn = sqlite3.connect(":memory:") diff --git a/Doc/includes/mp_benchmarks.py b/Doc/includes/mp_benchmarks.py --- a/Doc/includes/mp_benchmarks.py +++ b/Doc/includes/mp_benchmarks.py @@ -5,7 +5,12 @@ # All rights reserved. # -import time, sys, multiprocessing, threading, queue, gc +import time +import sys +import multiprocessing +import threading +import queue +import gc if sys.platform == 'win32': _timer = time.clock @@ -111,7 +116,7 @@ for i in range(iterations): a = seq[5] - elapsed = _timer()-t + elapsed = _timer() - t print(iterations, 'iterations in', elapsed, 'seconds') print('average number/sec:', iterations/elapsed) @@ -132,7 +137,7 @@ l.acquire() l.release() - elapsed = _timer()-t + elapsed = _timer() - t print(iterations, 'iterations in', elapsed, 'seconds') print('average number/sec:', iterations/elapsed) @@ -169,7 +174,7 @@ c.notify() c.wait() - elapsed = _timer()-t + elapsed = _timer() - t c.release() p.join() diff --git a/Doc/includes/mp_pool.py b/Doc/includes/mp_pool.py --- a/Doc/includes/mp_pool.py +++ b/Doc/includes/mp_pool.py @@ -25,18 +25,18 @@ return calculate(*args) def mul(a, b): - time.sleep(0.5*random.random()) + time.sleep(0.5 * random.random()) return a * b def plus(a, b): - time.sleep(0.5*random.random()) + time.sleep(0.5 * random.random()) return a + b def f(x): - return 1.0 / (x-5.0) + return 1.0 / (x - 5.0) def pow3(x): - return x**3 + return x ** 3 def noop(x): pass diff --git a/Doc/includes/mp_synchronize.py b/Doc/includes/mp_synchronize.py --- a/Doc/includes/mp_synchronize.py +++ b/Doc/includes/mp_synchronize.py @@ -5,7 +5,9 @@ # All rights reserved. # -import time, sys, random +import time +import sys +import random from queue import Empty import multiprocessing # may get overwritten @@ -237,9 +239,9 @@ multiprocessing = namespace - for func in [ test_value, test_queue, test_condition, - test_semaphore, test_join_timeout, test_event, - test_sharedvalues ]: + for func in [test_value, test_queue, test_condition, + test_semaphore, test_join_timeout, test_event, + test_sharedvalues]: print('\n\t######## %s\n' % func.__name__) func() diff --git a/Doc/includes/mp_webserver.py b/Doc/includes/mp_webserver.py --- a/Doc/includes/mp_webserver.py +++ b/Doc/includes/mp_webserver.py @@ -24,7 +24,7 @@ def note(format, *args): - sys.stderr.write('[%s]\t%s\n' % (current_process().name, format%args)) + sys.stderr.write('[%s]\t%s\n' % (current_process().name, format % args)) class RequestHandler(SimpleHTTPRequestHandler): @@ -45,7 +45,7 @@ server = HTTPServer(address, RequestHandler) # create child processes to act as workers - for i in range(number_of_processes-1): + for i in range(number_of_processes - 1): Process(target=serve_forever, args=(server,)).start() # main process also acts as a worker diff --git a/Doc/includes/sqlite3/adapter_datetime.py b/Doc/includes/sqlite3/adapter_datetime.py --- a/Doc/includes/sqlite3/adapter_datetime.py +++ b/Doc/includes/sqlite3/adapter_datetime.py @@ -1,5 +1,6 @@ import sqlite3 -import datetime, time +import datetime +import time def adapt_datetime(ts): return time.mktime(ts.timetuple()) diff --git a/Doc/includes/tzinfo-examples.py b/Doc/includes/tzinfo-examples.py --- a/Doc/includes/tzinfo-examples.py +++ b/Doc/includes/tzinfo-examples.py @@ -27,7 +27,7 @@ """Fixed offset in minutes east from UTC.""" def __init__(self, offset, name): - self.__offset = timedelta(minutes = offset) + self.__offset = timedelta(minutes=offset) self.__name = name def utcoffset(self, dt): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 26 23:00:16 2011 From: python-checkins at python.org (raymond.hettinger) Date: Tue, 26 Apr 2011 23:00:16 +0200 Subject: [Python-checkins] cpython (merge default -> default): merge Message-ID: http://hg.python.org/cpython/rev/a1c99fd58049 changeset: 69583:a1c99fd58049 parent: 69582:89fcadbc49df parent: 69580:ec754f8d2917 user: Raymond Hettinger date: Tue Apr 26 13:59:59 2011 -0700 summary: merge files: Doc/whatsnew/3.3.rst | 6 ++++++ Misc/NEWS | 3 +++ Modules/main.c | 1 + Modules/posixmodule.c | 2 ++ PC/os2emx/pyconfig.h | 2 ++ 5 files changed, 14 insertions(+), 0 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 @@ -136,6 +136,12 @@ * Stub +Unsupported operating systems +============================= + +OS/2 and VMS are no more supported because of the lack of maintainer. + + Porting to Python 3.3 ===================== diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #11918: OS/2 and VMS are no more supported because of the lack of + maintainer. + - Issue #6780: fix starts/endswith error message to mention that tuples are accepted too. diff --git a/Modules/main.c b/Modules/main.c --- a/Modules/main.c +++ b/Modules/main.c @@ -6,6 +6,7 @@ #include #ifdef __VMS +#error "PEP 11: VMS is now unsupported, code will be removed in Python 3.4" #include #endif diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -30,6 +30,7 @@ #include "Python.h" #if defined(__VMS) +# error "PEP 11: VMS is now unsupported, code will be removed in Python 3.4" # include #endif /* defined(__VMS) */ @@ -45,6 +46,7 @@ #if defined(PYOS_OS2) +#error "PEP 11: OS/2 is now unsupported, code will be removed in Python 3.4" #define INCL_DOS #define INCL_DOSERRORS #define INCL_DOSPROCESS diff --git a/PC/os2emx/pyconfig.h b/PC/os2emx/pyconfig.h --- a/PC/os2emx/pyconfig.h +++ b/PC/os2emx/pyconfig.h @@ -1,6 +1,8 @@ #ifndef Py_CONFIG_H #define Py_CONFIG_H +#error "PEP 11: OS/2 is now unsupported, code will be removed in Python 3.4" + /* config.h. * At some time in the past, generated automatically by/from configure. * now maintained manually. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 26 23:51:15 2011 From: python-checkins at python.org (victor.stinner) Date: Tue, 26 Apr 2011 23:51:15 +0200 Subject: [Python-checkins] cpython: PyGILState_Ensure(), PyGILState_Release(), PyGILState_GetThisThreadState() are Message-ID: http://hg.python.org/cpython/rev/75503c26a17f changeset: 69584:75503c26a17f user: Victor Stinner date: Tue Apr 26 23:34:58 2011 +0200 summary: PyGILState_Ensure(), PyGILState_Release(), PyGILState_GetThisThreadState() are not available if Python is compiled without threads. files: Include/pystate.h | 10 +++++++--- 1 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Include/pystate.h b/Include/pystate.h --- a/Include/pystate.h +++ b/Include/pystate.h @@ -73,9 +73,9 @@ struct _frame *frame; int recursion_depth; char overflowed; /* The stack has overflowed. Allow 50 more calls - to handle the runtime error. */ - char recursion_critical; /* The current calls must not cause - a stack overflow. */ + to handle the runtime error. */ + char recursion_critical; /* The current calls must not cause + a stack overflow. */ /* 'tracing' keeps track of the execution depth when tracing/profiling. This is to prevent the actual trace/profile code from being recorded in the trace/profile. */ @@ -158,6 +158,8 @@ enum {PyGILState_LOCKED, PyGILState_UNLOCKED} PyGILState_STATE; +#ifdef WITH_THREAD + /* Ensure that the current thread is ready to call the Python C API, regardless of the current state of Python, or of its thread lock. This may be called as many times as desired @@ -199,6 +201,8 @@ */ PyAPI_FUNC(PyThreadState *) PyGILState_GetThisThreadState(void); +#endif /* #ifdef WITH_THREAD */ + /* The implementation of sys._current_frames() Returns a dict mapping thread id to that thread's current frame. */ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Apr 26 23:51:16 2011 From: python-checkins at python.org (victor.stinner) Date: Tue, 26 Apr 2011 23:51:16 +0200 Subject: [Python-checkins] cpython: Fix compilation of _testembed.c without threads Message-ID: http://hg.python.org/cpython/rev/79fcd71d0356 changeset: 69585:79fcd71d0356 user: Victor Stinner date: Tue Apr 26 23:37:02 2011 +0200 summary: Fix compilation of _testembed.c without threads files: Modules/_testembed.c | 6 ++++++ 1 files changed, 6 insertions(+), 0 deletions(-) diff --git a/Modules/_testembed.c b/Modules/_testembed.c --- a/Modules/_testembed.c +++ b/Modules/_testembed.c @@ -17,7 +17,9 @@ int main(int argc, char *argv[]) { PyThreadState *mainstate, *substate; +#ifdef WITH_THREAD PyGILState_STATE gilstate; +#endif int i, j; for (i=0; i<3; i++) { @@ -28,10 +30,12 @@ Py_Initialize(); mainstate = PyThreadState_Get(); +#ifdef WITH_THREAD PyEval_InitThreads(); PyEval_ReleaseThread(mainstate); gilstate = PyGILState_Ensure(); +#endif print_subinterp(); PyThreadState_Swap(NULL); @@ -43,7 +47,9 @@ PyThreadState_Swap(mainstate); print_subinterp(); +#ifdef WITH_THREAD PyGILState_Release(gilstate); +#endif PyEval_RestoreThread(mainstate); Py_Finalize(); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 27 00:24:24 2011 From: python-checkins at python.org (victor.stinner) Date: Wed, 27 Apr 2011 00:24:24 +0200 Subject: [Python-checkins] cpython: Issue #10914: Py_NewInterpreter() uses PyErr_PrintEx(0) Message-ID: http://hg.python.org/cpython/rev/c8338cfa3578 changeset: 69586:c8338cfa3578 user: Victor Stinner date: Wed Apr 27 00:20:27 2011 +0200 summary: Issue #10914: Py_NewInterpreter() uses PyErr_PrintEx(0) ... instead of PyErr_Print() because we don't need to set sys attributes, the sys module is destroyed just after printing the error. files: Python/pythonrun.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Python/pythonrun.c b/Python/pythonrun.c --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -632,7 +632,7 @@ handle_error: /* Oops, it didn't work. Undo it all. */ - PyErr_Print(); + PyErr_PrintEx(0); PyThreadState_Clear(tstate); PyThreadState_Swap(save_tstate); PyThreadState_Delete(tstate); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 27 00:24:25 2011 From: python-checkins at python.org (victor.stinner) Date: Wed, 27 Apr 2011 00:24:25 +0200 Subject: [Python-checkins] cpython: Issue #10914: Initialize correctly the filesystem codec when creating a new Message-ID: http://hg.python.org/cpython/rev/d3af2a2b621b changeset: 69587:d3af2a2b621b user: Victor Stinner date: Wed Apr 27 00:24:21 2011 +0200 summary: Issue #10914: Initialize correctly the filesystem codec when creating a new subinterpreter to fix a bootstrap issue with codecs implemented in Python, as the ISO-8859-15 codec. Add fscodec_initialized attribute to the PyInterpreterState structure. files: Include/pystate.h | 1 + Misc/NEWS | 4 ++++ Objects/unicodeobject.c | 29 ++++++++++++++++++++++------- Python/pystate.c | 1 + Python/pythonrun.c | 23 +++++++++++++++-------- 5 files changed, 43 insertions(+), 15 deletions(-) diff --git a/Include/pystate.h b/Include/pystate.h --- a/Include/pystate.h +++ b/Include/pystate.h @@ -31,6 +31,7 @@ PyObject *codec_search_cache; PyObject *codec_error_registry; int codecs_initialized; + int fscodec_initialized; #ifdef HAVE_DLOPEN int dlopenflags; diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,10 @@ Core and Builtins ----------------- +- Issue #10914: Initialize correctly the filesystem codec when creating a new + subinterpreter to fix a bootstrap issue with codecs implemented in Python, as + the ISO-8859-15 codec. + - Issue #11918: OS/2 and VMS are no more supported because of the lack of maintainer. diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -1653,7 +1653,17 @@ PyUnicode_GET_SIZE(unicode), "surrogateescape"); #else - if (Py_FileSystemDefaultEncoding) { + PyInterpreterState *interp = PyThreadState_GET()->interp; + /* Bootstrap check: if the filesystem codec is implemented in Python, we + cannot use it to encode and decode filenames before it is loaded. Load + the Python codec requires to encode at least its own filename. Use the C + version of the locale codec until the codec registry is initialized and + the Python codec is loaded. + + Py_FileSystemDefaultEncoding is shared between all interpreters, we + cannot only rely on it: check also interp->fscodec_initialized for + subinterpreters. */ + if (Py_FileSystemDefaultEncoding && interp->fscodec_initialized) { return PyUnicode_AsEncodedString(unicode, Py_FileSystemDefaultEncoding, "surrogateescape"); @@ -1843,12 +1853,17 @@ #elif defined(__APPLE__) return PyUnicode_DecodeUTF8(s, size, "surrogateescape"); #else - /* During the early bootstrapping process, Py_FileSystemDefaultEncoding - can be undefined. If it is case, decode using UTF-8. The following assumes - that Py_FileSystemDefaultEncoding is set to a built-in encoding during the - bootstrapping process where the codecs aren't ready yet. - */ - if (Py_FileSystemDefaultEncoding) { + PyInterpreterState *interp = PyThreadState_GET()->interp; + /* Bootstrap check: if the filesystem codec is implemented in Python, we + cannot use it to encode and decode filenames before it is loaded. Load + the Python codec requires to encode at least its own filename. Use the C + version of the locale codec until the codec registry is initialized and + the Python codec is loaded. + + Py_FileSystemDefaultEncoding is shared between all interpreters, we + cannot only rely on it: check also interp->fscodec_initialized for + subinterpreters. */ + if (Py_FileSystemDefaultEncoding && interp->fscodec_initialized) { return PyUnicode_Decode(s, size, Py_FileSystemDefaultEncoding, "surrogateescape"); diff --git a/Python/pystate.c b/Python/pystate.c --- a/Python/pystate.c +++ b/Python/pystate.c @@ -79,6 +79,7 @@ interp->codec_search_cache = NULL; interp->codec_error_registry = NULL; interp->codecs_initialized = 0; + interp->fscodec_initialized = 0; #ifdef HAVE_DLOPEN #ifdef RTLD_NOW interp->dlopenflags = RTLD_NOW; diff --git a/Python/pythonrun.c b/Python/pythonrun.c --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -53,7 +53,7 @@ /* Forward */ static void initmain(void); -static void initfsencoding(void); +static int initfsencoding(PyInterpreterState *interp); static void initsite(void); static int initstdio(void); static void flush_io(void); @@ -298,7 +298,8 @@ _PyTime_Init(); - initfsencoding(); + if (initfsencoding(interp) < 0) + Py_FatalError("Py_Initialize: unable to load the file system codec"); if (install_sigs) initsigs(); /* Signal handling stuff, including initintr() */ @@ -618,6 +619,10 @@ Py_DECREF(pstderr); _PyImportHooks_Init(); + + if (initfsencoding(interp) < 0) + goto handle_error; + if (initstdio() < 0) Py_FatalError( "Py_Initialize: can't initialize sys standard streams"); @@ -730,8 +735,8 @@ } } -static void -initfsencoding(void) +static int +initfsencoding(PyInterpreterState *interp) { PyObject *codec; #if defined(HAVE_LANGINFO_H) && defined(CODESET) @@ -748,7 +753,8 @@ Py_FileSystemDefaultEncoding = codeset; Py_HasFileSystemDefaultEncoding = 0; - return; + interp->fscodec_initialized = 1; + return 0; } #endif @@ -758,10 +764,11 @@ /* Such error can only occurs in critical situations: no more * memory, import a module of the standard library failed, * etc. */ - Py_FatalError("Py_Initialize: unable to load the file system codec"); - } else { - Py_DECREF(codec); + return -1; } + Py_DECREF(codec); + interp->fscodec_initialized = 1; + return 0; } /* Import the site module (not into __main__ though) */ -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Wed Apr 27 04:58:07 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Wed, 27 Apr 2011 04:58:07 +0200 Subject: [Python-checkins] Daily reference leaks (d3af2a2b621b): sum=0 Message-ID: results for d3af2a2b621b on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogYd_nyw', '-x'] From python-checkins at python.org Wed Apr 27 09:21:37 2011 From: python-checkins at python.org (ezio.melotti) Date: Wed, 27 Apr 2011 09:21:37 +0200 Subject: [Python-checkins] cpython (2.7): #11763: don't use difflib in TestCase.assertMultiLineEqual if the strings are Message-ID: http://hg.python.org/cpython/rev/8dbf661c0a63 changeset: 69588:8dbf661c0a63 branch: 2.7 parent: 69573:1b261f3bef09 user: Ezio Melotti date: Wed Apr 27 09:45:46 2011 +0300 summary: #11763: don't use difflib in TestCase.assertMultiLineEqual if the strings are too long. files: Lib/unittest/case.py | 8 ++++ Lib/unittest/test/test_case.py | 36 ++++++++++++++++++++++ Misc/NEWS | 3 + 3 files changed, 47 insertions(+), 0 deletions(-) diff --git a/Lib/unittest/case.py b/Lib/unittest/case.py --- a/Lib/unittest/case.py +++ b/Lib/unittest/case.py @@ -169,6 +169,10 @@ maxDiff = 80*8 + # If a string is longer than _diffThreshold, use normal comparison instead + # of difflib. See #11763. + _diffThreshold = 2**16 + # Attribute used by TestSuite for classSetUp _classSetupFailed = False @@ -900,6 +904,10 @@ 'Second argument is not a string') if first != second: + # don't use difflib if the strings are too long + if (len(first) > self._diffThreshold or + len(second) > self._diffThreshold): + self._baseAssertEqual(first, second, msg) firstlines = first.splitlines(True) secondlines = second.splitlines(True) if len(firstlines) == 1 and first.strip('\r\n') == first: diff --git a/Lib/unittest/test/test_case.py b/Lib/unittest/test/test_case.py --- a/Lib/unittest/test/test_case.py +++ b/Lib/unittest/test/test_case.py @@ -667,6 +667,42 @@ else: self.fail('assertMultiLineEqual did not fail') + def testAssertEqual_diffThreshold(self): + # check threshold value + self.assertEqual(self._diffThreshold, 2**16) + # disable madDiff to get diff markers + self.maxDiff = None + + # set a lower threshold value and add a cleanup to restore it + old_threshold = self._diffThreshold + self._diffThreshold = 2**8 + self.addCleanup(lambda: setattr(self, '_diffThreshold', old_threshold)) + + # under the threshold: diff marker (^) in error message + s = u'x' * (2**7) + with self.assertRaises(self.failureException) as cm: + self.assertEqual(s + 'a', s + 'b') + self.assertIn('^', str(cm.exception)) + self.assertEqual(s + 'a', s + 'a') + + # over the threshold: diff not used and marker (^) not in error message + s = u'x' * (2**9) + # if the path that uses difflib is taken, _truncateMessage will be + # called -- replace it with explodingTruncation to verify that this + # doesn't happen + def explodingTruncation(message, diff): + raise SystemError('this should not be raised') + old_truncate = self._truncateMessage + self._truncateMessage = explodingTruncation + self.addCleanup(lambda: setattr(self, '_truncateMessage', old_truncate)) + + s1, s2 = s + 'a', s + 'b' + with self.assertRaises(self.failureException) as cm: + self.assertEqual(s1, s2) + self.assertNotIn('^', str(cm.exception)) + self.assertEqual(str(cm.exception), '%r != %r' % (s1, s2)) + self.assertEqual(s + 'a', s + 'a') + def testAssertItemsEqual(self): a = object() self.assertItemsEqual([1, 2, 3], [3, 2, 1]) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -61,6 +61,9 @@ Library ------- +- Issue #11763: don't use difflib in TestCase.assertMultiLineEqual if the + strings are too long. + - Issue #11236: getpass.getpass responds to ctrl-c or ctrl-z on terminal. - Issue #11768: The signal handler of the signal module only calls -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 27 09:21:37 2011 From: python-checkins at python.org (ezio.melotti) Date: Wed, 27 Apr 2011 09:21:37 +0200 Subject: [Python-checkins] cpython (3.1): #11763: don't use difflib in TestCase.assertMultiLineEqual if the strings are Message-ID: http://hg.python.org/cpython/rev/04e64f77c6c7 changeset: 69589:04e64f77c6c7 branch: 3.1 parent: 69569:f799530dbde7 user: Ezio Melotti date: Wed Apr 27 10:17:34 2011 +0300 summary: #11763: don't use difflib in TestCase.assertMultiLineEqual if the strings are too long. files: Lib/test/test_unittest.py | 35 +++++++++++++++++++++++++++ Lib/unittest.py | 7 +++++ Misc/NEWS | 3 ++ 3 files changed, 45 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_unittest.py b/Lib/test/test_unittest.py --- a/Lib/test/test_unittest.py +++ b/Lib/test/test_unittest.py @@ -2719,6 +2719,41 @@ # no fair testing ourself with ourself, use assertEqual.. self.assertEqual(sample_text_error, str(e)) + def testAssertEqual_diffThreshold(self): + # check threshold value + self.assertEqual(self._diffThreshold, 2**16) + # disable madDiff to get diff markers + self.maxDiff = None + + # set a lower threshold value and add a cleanup to restore it + old_threshold = self._diffThreshold + self._diffThreshold = 2**8 + self.addCleanup(lambda: setattr(self, '_diffThreshold', old_threshold)) + + # under the threshold: diff marker (^) in error message + s = 'x' * (2**7) + try: + self.assertMultiLineEqual(s + 'a', s + 'b') + except self.failureException as exc: + err_msg = str(exc) + else: + self.fail('assertEqual unexpectedly succeeded') + self.assertIn('^', err_msg) + self.assertMultiLineEqual(s + 'a', s + 'a') + + # over the threshold: diff not used and marker (^) not in error message + s = 'x' * (2**9) + s1, s2 = s + 'a', s + 'b' + try: + self.assertMultiLineEqual(s1, s2) + except self.failureException as exc: + err_msg = str(exc) + else: + self.fail('assertEqual unexpectedly succeeded') + self.assertNotIn('^', err_msg) + self.assertEqual(err_msg, '%r != %r' % (s1, s2)) + self.assertMultiLineEqual(s + 'a', s + 'a') + def testAssertIsNone(self): self.assertIsNone(None) self.assertRaises(self.failureException, self.assertIsNone, False) diff --git a/Lib/unittest.py b/Lib/unittest.py --- a/Lib/unittest.py +++ b/Lib/unittest.py @@ -346,6 +346,9 @@ longMessage = False + # If a string is longer than _diffThreshold, use normal comparison instead + # of difflib. See #11763. + _diffThreshold = 2**16 def __init__(self, methodName='runTest'): """Create an instance of the class that will use the named test @@ -955,6 +958,10 @@ 'Second argument is not a string')) if first != second: + # don't use difflib if the strings are too long + if (len(first) > self._diffThreshold or + len(second) > self._diffThreshold): + self._baseAssertEqual(first, second, msg) standardMsg = '\n' + ''.join(difflib.ndiff(first.splitlines(True), second.splitlines(True))) self.fail(self._formatMessage(msg, standardMsg)) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -61,6 +61,9 @@ Library ------- +- Issue #11763: don't use difflib in TestCase.assertMultiLineEqual if the + strings are too long. + - Issue #11236: getpass.getpass responds to ctrl-c or ctrl-z on terminal. - Issue #11768: The signal handler of the signal module only calls -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 27 09:21:41 2011 From: python-checkins at python.org (ezio.melotti) Date: Wed, 27 Apr 2011 09:21:41 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): #11763: merge with 3.1. Message-ID: http://hg.python.org/cpython/rev/b316019638df changeset: 69590:b316019638df branch: 3.2 parent: 69581:5e93c5cdc378 parent: 69589:04e64f77c6c7 user: Ezio Melotti date: Wed Apr 27 10:20:38 2011 +0300 summary: #11763: merge with 3.1. files: Lib/unittest/case.py | 8 ++++ Lib/unittest/test/test_case.py | 36 ++++++++++++++++++++++ Misc/NEWS | 3 + 3 files changed, 47 insertions(+), 0 deletions(-) diff --git a/Lib/unittest/case.py b/Lib/unittest/case.py --- a/Lib/unittest/case.py +++ b/Lib/unittest/case.py @@ -263,6 +263,10 @@ maxDiff = 80*8 + # If a string is longer than _diffThreshold, use normal comparison instead + # of difflib. See #11763. + _diffThreshold = 2**16 + # Attribute used by TestSuite for classSetUp _classSetupFailed = False @@ -1048,6 +1052,10 @@ self.assertIsInstance(second, str, 'Second argument is not a string') if first != second: + # don't use difflib if the strings are too long + if (len(first) > self._diffThreshold or + len(second) > self._diffThreshold): + self._baseAssertEqual(first, second, msg) firstlines = first.splitlines(True) secondlines = second.splitlines(True) if len(firstlines) == 1 and first.strip('\r\n') == first: diff --git a/Lib/unittest/test/test_case.py b/Lib/unittest/test/test_case.py --- a/Lib/unittest/test/test_case.py +++ b/Lib/unittest/test/test_case.py @@ -685,6 +685,42 @@ else: self.fail('assertMultiLineEqual did not fail') + def testAssertEqual_diffThreshold(self): + # check threshold value + self.assertEqual(self._diffThreshold, 2**16) + # disable madDiff to get diff markers + self.maxDiff = None + + # set a lower threshold value and add a cleanup to restore it + old_threshold = self._diffThreshold + self._diffThreshold = 2**8 + self.addCleanup(lambda: setattr(self, '_diffThreshold', old_threshold)) + + # under the threshold: diff marker (^) in error message + s = 'x' * (2**7) + with self.assertRaises(self.failureException) as cm: + self.assertEqual(s + 'a', s + 'b') + self.assertIn('^', str(cm.exception)) + self.assertEqual(s + 'a', s + 'a') + + # over the threshold: diff not used and marker (^) not in error message + s = 'x' * (2**9) + # if the path that uses difflib is taken, _truncateMessage will be + # called -- replace it with explodingTruncation to verify that this + # doesn't happen + def explodingTruncation(message, diff): + raise SystemError('this should not be raised') + old_truncate = self._truncateMessage + self._truncateMessage = explodingTruncation + self.addCleanup(lambda: setattr(self, '_truncateMessage', old_truncate)) + + s1, s2 = s + 'a', s + 'b' + with self.assertRaises(self.failureException) as cm: + self.assertEqual(s1, s2) + self.assertNotIn('^', str(cm.exception)) + self.assertEqual(str(cm.exception), '%r != %r' % (s1, s2)) + self.assertEqual(s + 'a', s + 'a') + def testAssertCountEqual(self): a = object() self.assertCountEqual([1, 2, 3], [3, 2, 1]) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -66,6 +66,9 @@ Library ------- +- Issue #11763: don't use difflib in TestCase.assertMultiLineEqual if the + strings are too long. + - Issue #11236: getpass.getpass responds to ctrl-c or ctrl-z on terminal. - Issue #11768: The signal handler of the signal module only calls -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 27 09:21:44 2011 From: python-checkins at python.org (ezio.melotti) Date: Wed, 27 Apr 2011 09:21:44 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): #11763: merge with 3.2. Message-ID: http://hg.python.org/cpython/rev/df154c872b0c changeset: 69591:df154c872b0c parent: 69587:d3af2a2b621b parent: 69590:b316019638df user: Ezio Melotti date: Wed Apr 27 10:21:51 2011 +0300 summary: #11763: merge with 3.2. files: Lib/unittest/case.py | 8 ++++ Lib/unittest/test/test_case.py | 36 ++++++++++++++++++++++ Misc/NEWS | 3 + 3 files changed, 47 insertions(+), 0 deletions(-) diff --git a/Lib/unittest/case.py b/Lib/unittest/case.py --- a/Lib/unittest/case.py +++ b/Lib/unittest/case.py @@ -263,6 +263,10 @@ maxDiff = 80*8 + # If a string is longer than _diffThreshold, use normal comparison instead + # of difflib. See #11763. + _diffThreshold = 2**16 + # Attribute used by TestSuite for classSetUp _classSetupFailed = False @@ -1006,6 +1010,10 @@ self.assertIsInstance(second, str, 'Second argument is not a string') if first != second: + # don't use difflib if the strings are too long + if (len(first) > self._diffThreshold or + len(second) > self._diffThreshold): + self._baseAssertEqual(first, second, msg) firstlines = first.splitlines(True) secondlines = second.splitlines(True) if len(firstlines) == 1 and first.strip('\r\n') == first: diff --git a/Lib/unittest/test/test_case.py b/Lib/unittest/test/test_case.py --- a/Lib/unittest/test/test_case.py +++ b/Lib/unittest/test/test_case.py @@ -720,6 +720,42 @@ else: self.fail('assertMultiLineEqual did not fail') + def testAssertEqual_diffThreshold(self): + # check threshold value + self.assertEqual(self._diffThreshold, 2**16) + # disable madDiff to get diff markers + self.maxDiff = None + + # set a lower threshold value and add a cleanup to restore it + old_threshold = self._diffThreshold + self._diffThreshold = 2**8 + self.addCleanup(lambda: setattr(self, '_diffThreshold', old_threshold)) + + # under the threshold: diff marker (^) in error message + s = 'x' * (2**7) + with self.assertRaises(self.failureException) as cm: + self.assertEqual(s + 'a', s + 'b') + self.assertIn('^', str(cm.exception)) + self.assertEqual(s + 'a', s + 'a') + + # over the threshold: diff not used and marker (^) not in error message + s = 'x' * (2**9) + # if the path that uses difflib is taken, _truncateMessage will be + # called -- replace it with explodingTruncation to verify that this + # doesn't happen + def explodingTruncation(message, diff): + raise SystemError('this should not be raised') + old_truncate = self._truncateMessage + self._truncateMessage = explodingTruncation + self.addCleanup(lambda: setattr(self, '_truncateMessage', old_truncate)) + + s1, s2 = s + 'a', s + 'b' + with self.assertRaises(self.failureException) as cm: + self.assertEqual(s1, s2) + self.assertNotIn('^', str(cm.exception)) + self.assertEqual(str(cm.exception), '%r != %r' % (s1, s2)) + self.assertEqual(s + 'a', s + 'a') + def testAssertCountEqual(self): a = object() self.assertCountEqual([1, 2, 3], [3, 2, 1]) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -123,6 +123,9 @@ Library ------- +- Issue #11763: don't use difflib in TestCase.assertMultiLineEqual if the + strings are too long. + - Issue #11236: getpass.getpass responds to ctrl-c or ctrl-z on terminal. - Issue #11856: Speed up parsing of JSON numbers. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 27 09:30:57 2011 From: python-checkins at python.org (vinay.sajip) Date: Wed, 27 Apr 2011 09:30:57 +0200 Subject: [Python-checkins] cpython: Re-enabled time test in test_logging. Message-ID: http://hg.python.org/cpython/rev/e3ac9fd27525 changeset: 69592:e3ac9fd27525 user: Vinay Sajip date: Wed Apr 27 08:30:30 2011 +0100 summary: Re-enabled time test in test_logging. files: Lib/test/test_logging.py | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) 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 @@ -2279,10 +2279,10 @@ def test_invalid_style(self): self.assertRaises(ValueError, logging.Formatter, None, None, 'x') - def disabled_test_time(self): + def test_time(self): r = self.get_record() dt = datetime.datetime(1993,4,21,8,3,0,0,utc) - r.created = time.mktime(dt.utctimetuple()) + r.created = time.mktime(dt.timetuple()) - time.timezone r.msecs = 123 f = logging.Formatter('%(asctime)s %(message)s') f.converter = time.gmtime -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 27 12:31:42 2011 From: python-checkins at python.org (vinay.sajip) Date: Wed, 27 Apr 2011 12:31:42 +0200 Subject: [Python-checkins] cpython: test_logging coverage improvements. Message-ID: http://hg.python.org/cpython/rev/fbac8f321937 changeset: 69593:fbac8f321937 user: Vinay Sajip date: Wed Apr 27 11:31:14 2011 +0100 summary: test_logging coverage improvements. files: Lib/logging/handlers.py | 4 +- Lib/test/test_logging.py | 46 ++++++++++++++++++++++++++- 2 files changed, 46 insertions(+), 4 deletions(-) diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py --- a/Lib/logging/handlers.py +++ b/Lib/logging/handlers.py @@ -713,10 +713,10 @@ self.socktype = socktype if isinstance(address, str): - self.unixsocket = 1 + self.unixsocket = True self._connect_unixsocket(address) else: - self.unixsocket = 0 + self.unixsocket = False self.socket = socket.socket(socket.AF_INET, socktype) if socktype == socket.SOCK_STREAM: self.socket.connect(address) 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 @@ -508,8 +508,50 @@ self.assertEqual(h.name, 'anothergeneric') self.assertRaises(NotImplementedError, h.emit, None) - def test_abc(self): - pass + def test_builtin_handlers(self): + # We can't actually *use* too many handlers in the tests, + # but we can try instantiating them with various options + if sys.platform in ('linux2', 'darwin'): + for existing in (True, False): + fd, fn = tempfile.mkstemp() + os.close(fd) + if not existing: + os.unlink(fn) + h = logging.handlers.WatchedFileHandler(fn, delay=True) + if existing: + self.assertNotEqual(h.dev, -1) + self.assertNotEqual(h.ino, -1) + else: + self.assertEqual(h.dev, -1) + self.assertEqual(h.ino, -1) + h.close() + if existing: + os.unlink(fn) + if sys.platform == 'darwin': + sockname = '/var/run/log' + else: + sockname = '/dev/log' + h = logging.handlers.SysLogHandler(sockname) + self.assertEqual(h.facility, h.LOG_USER) + self.assertTrue(h.unixsocket) + h.close() + h = logging.handlers.SMTPHandler('localhost', 'me', 'you', 'Log') + self.assertEqual(h.toaddrs, ['you']) + h.close() + for method in ('GET', 'POST', 'PUT'): + if method == 'PUT': + self.assertRaises(ValueError, logging.handlers.HTTPHandler, + 'localhost', '/log', method) + else: + h = logging.handlers.HTTPHandler('localhost', '/log', method) + h.close() + h = logging.handlers.BufferingHandler(0) + r = logging.makeLogRecord({}) + self.assertTrue(h.shouldFlush(r)) + h.close() + h = logging.handlers.BufferingHandler(1) + self.assertFalse(h.shouldFlush(r)) + h.close() class BadStream(object): def write(self, data): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 27 15:18:36 2011 From: python-checkins at python.org (vinay.sajip) Date: Wed, 27 Apr 2011 15:18:36 +0200 Subject: [Python-checkins] cpython: test_logging: handle syslogd connection failure. Message-ID: http://hg.python.org/cpython/rev/ec0120219925 changeset: 69594:ec0120219925 user: Vinay Sajip date: Wed Apr 27 14:18:06 2011 +0100 summary: test_logging: handle syslogd connection failure. files: Lib/test/test_logging.py | 11 +++++++---- 1 files changed, 7 insertions(+), 4 deletions(-) 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 @@ -531,10 +531,13 @@ sockname = '/var/run/log' else: sockname = '/dev/log' - h = logging.handlers.SysLogHandler(sockname) - self.assertEqual(h.facility, h.LOG_USER) - self.assertTrue(h.unixsocket) - h.close() + try: + h = logging.handlers.SysLogHandler(sockname) + self.assertEqual(h.facility, h.LOG_USER) + self.assertTrue(h.unixsocket) + h.close() + except socket.error: # syslogd might not be available + pass h = logging.handlers.SMTPHandler('localhost', 'me', 'you', 'Log') self.assertEqual(h.toaddrs, ['you']) h.close() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 27 15:32:23 2011 From: python-checkins at python.org (vinay.sajip) Date: Wed, 27 Apr 2011 15:32:23 +0200 Subject: [Python-checkins] cpython: Use correct Unix socket for syslogd on OS X. Message-ID: http://hg.python.org/cpython/rev/4e7151c972a2 changeset: 69595:4e7151c972a2 user: Vinay Sajip date: Wed Apr 27 14:31:55 2011 +0100 summary: Use correct Unix socket for syslogd on OS X. files: Lib/test/test_logging.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) 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 @@ -528,7 +528,7 @@ if existing: os.unlink(fn) if sys.platform == 'darwin': - sockname = '/var/run/log' + sockname = '/var/run/syslog' else: sockname = '/dev/log' try: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 27 16:37:34 2011 From: python-checkins at python.org (eric.araujo) Date: Wed, 27 Apr 2011 16:37:34 +0200 Subject: [Python-checkins] cpython (3.1): Kill last reference to defunct module Message-ID: http://hg.python.org/cpython/rev/97c31d27456e changeset: 69596:97c31d27456e branch: 3.1 parent: 68951:ec25055d30f1 user: ?ric Araujo date: Sat Mar 26 07:22:01 2011 +0100 summary: Kill last reference to defunct module files: Doc/c-api/intro.rst | 3 +-- 1 files changed, 1 insertions(+), 2 deletions(-) diff --git a/Doc/c-api/intro.rst b/Doc/c-api/intro.rst --- a/Doc/c-api/intro.rst +++ b/Doc/c-api/intro.rst @@ -511,13 +511,12 @@ module: builtins module: __main__ module: sys - module: exceptions triple: module; search; path single: path (in module sys) The basic initialization function is :cfunc:`Py_Initialize`. This initializes the table of loaded modules, and creates the fundamental modules -:mod:`builtins`, :mod:`__main__`, :mod:`sys`, and :mod:`exceptions`. It also +:mod:`builtins`, :mod:`__main__`, and :mod:`sys`. It also initializes the module search path (``sys.path``). .. index:: single: PySys_SetArgv() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 27 16:37:35 2011 From: python-checkins at python.org (eric.araujo) Date: Wed, 27 Apr 2011 16:37:35 +0200 Subject: [Python-checkins] cpython (3.1): Minor tweaks to a few comments in heapq Message-ID: http://hg.python.org/cpython/rev/e0205b4a0807 changeset: 69597:e0205b4a0807 branch: 3.1 user: ?ric Araujo date: Fri Apr 15 23:34:31 2011 +0200 summary: Minor tweaks to a few comments in heapq files: Lib/heapq.py | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Lib/heapq.py b/Lib/heapq.py --- a/Lib/heapq.py +++ b/Lib/heapq.py @@ -172,7 +172,7 @@ return item def heapify(x): - """Transform list into a heap, in-place, in O(len(heap)) time.""" + """Transform list into a heap, in-place, in O(len(x)) time.""" n = len(x) # Transform bottom-up. The largest index there's any point to looking at # is the largest with a child index in-range, so must have 2*i + 1 < n, @@ -363,7 +363,7 @@ return [min(chain(head, it))] return [min(chain(head, it), key=key)] - # When n>=size, it's faster to use sort() + # When n>=size, it's faster to use sorted() try: size = len(iterable) except (TypeError, AttributeError): @@ -401,7 +401,7 @@ return [max(chain(head, it))] return [max(chain(head, it), key=key)] - # When n>=size, it's faster to use sort() + # When n>=size, it's faster to use sorted() try: size = len(iterable) except (TypeError, AttributeError): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 27 16:37:36 2011 From: python-checkins at python.org (eric.araujo) Date: Wed, 27 Apr 2011 16:37:36 +0200 Subject: [Python-checkins] cpython (3.1): Fix improper tests in RegisterTestCase Message-ID: http://hg.python.org/cpython/rev/da9fb61d5e1b changeset: 69598:da9fb61d5e1b branch: 3.1 user: ?ric Araujo date: Thu Apr 14 03:49:19 2011 +0200 summary: Fix improper tests in RegisterTestCase files: Lib/distutils/tests/test_register.py | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Lib/distutils/tests/test_register.py b/Lib/distutils/tests/test_register.py --- a/Lib/distutils/tests/test_register.py +++ b/Lib/distutils/tests/test_register.py @@ -137,7 +137,7 @@ # let's see what the server received : we should # have 2 similar requests - self.assertTrue(self.conn.reqs, 2) + self.assertEqual(len(self.conn.reqs), 2) req1 = dict(self.conn.reqs[0].headers) req2 = dict(self.conn.reqs[1].headers) @@ -169,7 +169,7 @@ del register_module.input # we should have send a request - self.assertTrue(self.conn.reqs, 1) + self.assertEqual(len(self.conn.reqs), 1) req = self.conn.reqs[0] headers = dict(req.headers) self.assertEqual(headers['Content-length'], '608') @@ -187,7 +187,7 @@ del register_module.input # we should have send a request - self.assertTrue(self.conn.reqs, 1) + self.assertEqual(len(self.conn.reqs), 1) req = self.conn.reqs[0] headers = dict(req.headers) self.assertEqual(headers['Content-length'], '290') -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 27 16:37:41 2011 From: python-checkins at python.org (eric.araujo) Date: Wed, 27 Apr 2011 16:37:41 +0200 Subject: [Python-checkins] cpython (3.1): Advertise nesting directives for class/method and class/data combos. Message-ID: http://hg.python.org/cpython/rev/584f9c213a6d changeset: 69599:584f9c213a6d branch: 3.1 user: ?ric Araujo date: Sat Apr 16 23:47:53 2011 +0200 summary: Advertise nesting directives for class/method and class/data combos. Also fix a typo and a misleading example (method used to describe function). files: Doc/documenting/markup.rst | 25 +++++++++++++++++++++---- 1 files changed, 21 insertions(+), 4 deletions(-) diff --git a/Doc/documenting/markup.rst b/Doc/documenting/markup.rst --- a/Doc/documenting/markup.rst +++ b/Doc/documenting/markup.rst @@ -152,7 +152,7 @@ Describes global data in a module, including both variables and values used as "defined constants." Class and object attributes are not documented - using this environment. + using this directive. .. describe:: exception @@ -165,7 +165,7 @@ parameters, enclosing optional parameters in brackets. Default values can be given if it enhances clarity. For example:: - .. function:: Timer.repeat([repeat=3[, number=1000000]]) + .. function:: repeat([repeat=3[, number=1000000]]) Object methods are not documented using this directive. Bound object methods placed in the module namespace as part of the public interface of the module @@ -186,13 +186,30 @@ Describes an object data attribute. The description should include information about the type of the data to be expected and whether it may be - changed directly. + changed directly. This directive should be nested in a class directive, + like in this example:: + + .. class:: Spam + + Description of the class. + + .. data:: ham + + Description of the attribute. + + If is also possible to document an attribute outside of a class directive, + for example if the documentation for different attributes and methods is + split in multiple sections. The class name should then be included + explicitly:: + + .. data:: Spam.eggs .. describe:: method Describes an object method. The parameters should not include the ``self`` parameter. The description should include similar information to that - described for ``function``. + described for ``function``. This method should be nested in a class + method, like in the example above. .. describe:: opcode -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 27 16:37:45 2011 From: python-checkins at python.org (eric.araujo) Date: Wed, 27 Apr 2011 16:37:45 +0200 Subject: [Python-checkins] cpython (3.1): Fix resource warning found manually Message-ID: http://hg.python.org/cpython/rev/316d792bf75b changeset: 69600:316d792bf75b branch: 3.1 user: ?ric Araujo date: Sun Apr 17 14:27:07 2011 +0200 summary: Fix resource warning found manually files: Lib/distutils/command/sdist.py | 23 ++++++++++++--------- 1 files changed, 13 insertions(+), 10 deletions(-) diff --git a/Lib/distutils/command/sdist.py b/Lib/distutils/command/sdist.py --- a/Lib/distutils/command/sdist.py +++ b/Lib/distutils/command/sdist.py @@ -294,17 +294,20 @@ join_lines=1, lstrip_ws=1, rstrip_ws=1, collapse_join=1) - while True: - line = template.readline() - if line is None: # end of file - break + try: + while True: + line = template.readline() + if line is None: # end of file + break - try: - self.filelist.process_template_line(line) - except DistutilsTemplateError as msg: - self.warn("%s, line %d: %s" % (template.filename, - template.current_line, - msg)) + try: + self.filelist.process_template_line(line) + except DistutilsTemplateError as msg: + self.warn("%s, line %d: %s" % (template.filename, + template.current_line, + msg)) + finally: + template.close() def prune_file_list(self): """Prune off branches that might slip into the file list as created -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 27 16:37:48 2011 From: python-checkins at python.org (eric.araujo) Date: Wed, 27 Apr 2011 16:37:48 +0200 Subject: [Python-checkins] cpython (3.1): Add docstring to dbm.open Message-ID: http://hg.python.org/cpython/rev/7601c8256a3d changeset: 69601:7601c8256a3d branch: 3.1 user: ?ric Araujo date: Wed Apr 20 18:52:55 2011 +0200 summary: Add docstring to dbm.open files: Lib/dbm/__init__.py | 22 ++++++++++++---------- 1 files changed, 12 insertions(+), 10 deletions(-) diff --git a/Lib/dbm/__init__.py b/Lib/dbm/__init__.py --- a/Lib/dbm/__init__.py +++ b/Lib/dbm/__init__.py @@ -24,16 +24,8 @@ list = d.keys() # return a list of all existing keys (slow!) Future versions may change the order in which implementations are -tested for existence, add interfaces to other dbm-like +tested for existence, and add interfaces to other dbm-like implementations. - -The open function has an optional second argument. This can be 'r', -for read-only access, 'w', for read-write access of an existing -database, 'c' for read-write access to a new or existing database, and -'n' for read-write access to a new database. The default is 'r'. - -Note: 'r' and 'w' fail if the database doesn't exist; 'c' creates it -only if it doesn't exist; and 'n' always creates a new database. """ __all__ = ['open', 'whichdb', 'error', 'error'] @@ -54,7 +46,17 @@ error = (error, IOError) -def open(file, flag = 'r', mode = 0o666): +def open(file, flag='r', mode=0o666): + """Open or create database at path given by *file*. + + Optional argument *flag* can be 'r' (default) for read-only access, 'w' + for read-write access of an existing database, 'c' for read-write access + to a new or existing database, and 'n' for read-write access to a new + database. + + Note: 'r' and 'w' fail if the database doesn't exist; 'c' creates it + only if it doesn't exist; and 'n' always creates a new database. + """ global _defaultmod if _defaultmod is None: for name in _names: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 27 16:37:52 2011 From: python-checkins at python.org (eric.araujo) Date: Wed, 27 Apr 2011 16:37:52 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.1): Branch merge Message-ID: http://hg.python.org/cpython/rev/d7f15f056174 changeset: 69602:d7f15f056174 branch: 3.1 parent: 69433:8b7b3748f876 parent: 69601:7601c8256a3d user: ?ric Araujo date: Wed Apr 20 18:54:12 2011 +0200 summary: Branch merge files: Doc/c-api/intro.rst | 3 +- Doc/documenting/markup.rst | 25 +++++++++++++-- Lib/dbm/__init__.py | 22 +++++++------ Lib/distutils/command/sdist.py | 23 ++++++++------ Lib/distutils/tests/test_register.py | 6 +- Lib/heapq.py | 6 +- 6 files changed, 53 insertions(+), 32 deletions(-) diff --git a/Doc/c-api/intro.rst b/Doc/c-api/intro.rst --- a/Doc/c-api/intro.rst +++ b/Doc/c-api/intro.rst @@ -511,13 +511,12 @@ module: builtins module: __main__ module: sys - module: exceptions triple: module; search; path single: path (in module sys) The basic initialization function is :cfunc:`Py_Initialize`. This initializes the table of loaded modules, and creates the fundamental modules -:mod:`builtins`, :mod:`__main__`, :mod:`sys`, and :mod:`exceptions`. It also +:mod:`builtins`, :mod:`__main__`, and :mod:`sys`. It also initializes the module search path (``sys.path``). .. index:: single: PySys_SetArgv() diff --git a/Doc/documenting/markup.rst b/Doc/documenting/markup.rst --- a/Doc/documenting/markup.rst +++ b/Doc/documenting/markup.rst @@ -152,7 +152,7 @@ Describes global data in a module, including both variables and values used as "defined constants." Class and object attributes are not documented - using this environment. + using this directive. .. describe:: exception @@ -165,7 +165,7 @@ parameters, enclosing optional parameters in brackets. Default values can be given if it enhances clarity. For example:: - .. function:: Timer.repeat([repeat=3[, number=1000000]]) + .. function:: repeat([repeat=3[, number=1000000]]) Object methods are not documented using this directive. Bound object methods placed in the module namespace as part of the public interface of the module @@ -186,13 +186,30 @@ Describes an object data attribute. The description should include information about the type of the data to be expected and whether it may be - changed directly. + changed directly. This directive should be nested in a class directive, + like in this example:: + + .. class:: Spam + + Description of the class. + + .. data:: ham + + Description of the attribute. + + If is also possible to document an attribute outside of a class directive, + for example if the documentation for different attributes and methods is + split in multiple sections. The class name should then be included + explicitly:: + + .. data:: Spam.eggs .. describe:: method Describes an object method. The parameters should not include the ``self`` parameter. The description should include similar information to that - described for ``function``. + described for ``function``. This method should be nested in a class + method, like in the example above. .. describe:: opcode diff --git a/Lib/dbm/__init__.py b/Lib/dbm/__init__.py --- a/Lib/dbm/__init__.py +++ b/Lib/dbm/__init__.py @@ -24,16 +24,8 @@ list = d.keys() # return a list of all existing keys (slow!) Future versions may change the order in which implementations are -tested for existence, add interfaces to other dbm-like +tested for existence, and add interfaces to other dbm-like implementations. - -The open function has an optional second argument. This can be 'r', -for read-only access, 'w', for read-write access of an existing -database, 'c' for read-write access to a new or existing database, and -'n' for read-write access to a new database. The default is 'r'. - -Note: 'r' and 'w' fail if the database doesn't exist; 'c' creates it -only if it doesn't exist; and 'n' always creates a new database. """ __all__ = ['open', 'whichdb', 'error', 'error'] @@ -54,7 +46,17 @@ error = (error, IOError) -def open(file, flag = 'r', mode = 0o666): +def open(file, flag='r', mode=0o666): + """Open or create database at path given by *file*. + + Optional argument *flag* can be 'r' (default) for read-only access, 'w' + for read-write access of an existing database, 'c' for read-write access + to a new or existing database, and 'n' for read-write access to a new + database. + + Note: 'r' and 'w' fail if the database doesn't exist; 'c' creates it + only if it doesn't exist; and 'n' always creates a new database. + """ global _defaultmod if _defaultmod is None: for name in _names: diff --git a/Lib/distutils/command/sdist.py b/Lib/distutils/command/sdist.py --- a/Lib/distutils/command/sdist.py +++ b/Lib/distutils/command/sdist.py @@ -294,17 +294,20 @@ join_lines=1, lstrip_ws=1, rstrip_ws=1, collapse_join=1) - while True: - line = template.readline() - if line is None: # end of file - break + try: + while True: + line = template.readline() + if line is None: # end of file + break - try: - self.filelist.process_template_line(line) - except DistutilsTemplateError as msg: - self.warn("%s, line %d: %s" % (template.filename, - template.current_line, - msg)) + try: + self.filelist.process_template_line(line) + except DistutilsTemplateError as msg: + self.warn("%s, line %d: %s" % (template.filename, + template.current_line, + msg)) + finally: + template.close() def prune_file_list(self): """Prune off branches that might slip into the file list as created diff --git a/Lib/distutils/tests/test_register.py b/Lib/distutils/tests/test_register.py --- a/Lib/distutils/tests/test_register.py +++ b/Lib/distutils/tests/test_register.py @@ -137,7 +137,7 @@ # let's see what the server received : we should # have 2 similar requests - self.assertTrue(self.conn.reqs, 2) + self.assertEqual(len(self.conn.reqs), 2) req1 = dict(self.conn.reqs[0].headers) req2 = dict(self.conn.reqs[1].headers) @@ -169,7 +169,7 @@ del register_module.input # we should have send a request - self.assertTrue(self.conn.reqs, 1) + self.assertEqual(len(self.conn.reqs), 1) req = self.conn.reqs[0] headers = dict(req.headers) self.assertEqual(headers['Content-length'], '608') @@ -187,7 +187,7 @@ del register_module.input # we should have send a request - self.assertTrue(self.conn.reqs, 1) + self.assertEqual(len(self.conn.reqs), 1) req = self.conn.reqs[0] headers = dict(req.headers) self.assertEqual(headers['Content-length'], '290') diff --git a/Lib/heapq.py b/Lib/heapq.py --- a/Lib/heapq.py +++ b/Lib/heapq.py @@ -172,7 +172,7 @@ return item def heapify(x): - """Transform list into a heap, in-place, in O(len(heap)) time.""" + """Transform list into a heap, in-place, in O(len(x)) time.""" n = len(x) # Transform bottom-up. The largest index there's any point to looking at # is the largest with a child index in-range, so must have 2*i + 1 < n, @@ -363,7 +363,7 @@ return [min(chain(head, it))] return [min(chain(head, it), key=key)] - # When n>=size, it's faster to use sort() + # When n>=size, it's faster to use sorted() try: size = len(iterable) except (TypeError, AttributeError): @@ -401,7 +401,7 @@ return [max(chain(head, it))] return [max(chain(head, it), key=key)] - # When n>=size, it's faster to use sort() + # When n>=size, it's faster to use sorted() try: size = len(iterable) except (TypeError, AttributeError): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 27 16:37:53 2011 From: python-checkins at python.org (eric.araujo) Date: Wed, 27 Apr 2011 16:37:53 +0200 Subject: [Python-checkins] cpython (3.1): Fix argument name in reST doc to match the code Message-ID: http://hg.python.org/cpython/rev/acaec4d48023 changeset: 69603:acaec4d48023 branch: 3.1 user: ?ric Araujo date: Wed Apr 20 19:11:12 2011 +0200 summary: Fix argument name in reST doc to match the code files: Doc/library/dbm.rst | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/dbm.rst b/Doc/library/dbm.rst --- a/Doc/library/dbm.rst +++ b/Doc/library/dbm.rst @@ -30,9 +30,9 @@ name, such as ``'dbm.ndbm'`` or ``'dbm.gnu'``. -.. function:: open(filename, flag='r', mode=0o666) +.. function:: open(file, flag='r', mode=0o666) - Open the database file *filename* and return a corresponding object. + Open the database file *file* and return a corresponding object. If the database file already exists, the :func:`whichdb` function is used to determine its type and the appropriate module is used; if it does not exist, -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 27 16:37:55 2011 From: python-checkins at python.org (eric.araujo) Date: Wed, 27 Apr 2011 16:37:55 +0200 Subject: [Python-checkins] cpython (3.2): Prevent deprecation warning Message-ID: http://hg.python.org/cpython/rev/c9792d3166eb changeset: 69604:c9792d3166eb branch: 3.2 parent: 69392:2596389a993d user: ?ric Araujo date: Sun Apr 17 16:48:52 2011 +0200 summary: Prevent deprecation warning files: Lib/trace.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/trace.py b/Lib/trace.py --- a/Lib/trace.py +++ b/Lib/trace.py @@ -688,7 +688,7 @@ for opt, val in opts: if opt == "--help": - usage(sys.stdout) + _usage(sys.stdout) sys.exit(0) if opt == "--version": -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 27 16:38:04 2011 From: python-checkins at python.org (eric.araujo) Date: Wed, 27 Apr 2011 16:38:04 +0200 Subject: [Python-checkins] cpython (3.2): Add missing types to docstring of ast.literal_eval. Message-ID: http://hg.python.org/cpython/rev/281c090ad3b9 changeset: 69605:281c090ad3b9 branch: 3.2 user: ?ric Araujo date: Sun Apr 17 19:10:27 2011 +0200 summary: Add missing types to docstring of ast.literal_eval. The reST doc was updated but not the docstring. files: Lib/ast.py | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/ast.py b/Lib/ast.py --- a/Lib/ast.py +++ b/Lib/ast.py @@ -40,8 +40,8 @@ """ Safely evaluate an expression node or a string containing a Python expression. The string or node provided may only consist of the following - Python literal structures: strings, numbers, tuples, lists, dicts, booleans, - and None. + Python literal structures: strings, bytes, numbers, tuples, lists, dicts, + sets, booleans, and None. """ _safe_names = {'None': None, 'True': True, 'False': False} if isinstance(node_or_string, str): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 27 16:38:05 2011 From: python-checkins at python.org (eric.araujo) Date: Wed, 27 Apr 2011 16:38:05 +0200 Subject: [Python-checkins] cpython (3.2): Fix double use of f.close(). Message-ID: http://hg.python.org/cpython/rev/85fefd41ef5d changeset: 69606:85fefd41ef5d branch: 3.2 user: ?ric Araujo date: Sat Apr 16 00:13:39 2011 +0200 summary: Fix double use of f.close(). The other one is in a finally block not seen in the diff, which I added in 3bf86785cd9c (for #10252). files: Lib/sysconfig.py | 1 - 1 files changed, 0 insertions(+), 1 deletions(-) diff --git a/Lib/sysconfig.py b/Lib/sysconfig.py --- a/Lib/sysconfig.py +++ b/Lib/sysconfig.py @@ -694,7 +694,6 @@ m = re.search( r'ProductUserVisibleVersion\s*' + r'(.*?)', f.read()) - f.close() if m is not None: macrelease = '.'.join(m.group(1).split('.')[:2]) # else: fall back to the default behaviour -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 27 16:38:07 2011 From: python-checkins at python.org (eric.araujo) Date: Wed, 27 Apr 2011 16:38:07 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> 3.2): Branch merge Message-ID: http://hg.python.org/cpython/rev/226b7a551931 changeset: 69607:226b7a551931 branch: 3.2 parent: 69439:d4bc42400692 parent: 69606:85fefd41ef5d user: ?ric Araujo date: Wed Apr 20 19:23:26 2011 +0200 summary: Branch merge files: Lib/ast.py | 4 ++-- Lib/sysconfig.py | 1 - Lib/trace.py | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Lib/ast.py b/Lib/ast.py --- a/Lib/ast.py +++ b/Lib/ast.py @@ -40,8 +40,8 @@ """ Safely evaluate an expression node or a string containing a Python expression. The string or node provided may only consist of the following - Python literal structures: strings, numbers, tuples, lists, dicts, booleans, - and None. + Python literal structures: strings, bytes, numbers, tuples, lists, dicts, + sets, booleans, and None. """ _safe_names = {'None': None, 'True': True, 'False': False} if isinstance(node_or_string, str): diff --git a/Lib/sysconfig.py b/Lib/sysconfig.py --- a/Lib/sysconfig.py +++ b/Lib/sysconfig.py @@ -694,7 +694,6 @@ m = re.search( r'ProductUserVisibleVersion\s*' + r'(.*?)', f.read()) - f.close() if m is not None: macrelease = '.'.join(m.group(1).split('.')[:2]) # else: fall back to the default behaviour diff --git a/Lib/trace.py b/Lib/trace.py --- a/Lib/trace.py +++ b/Lib/trace.py @@ -688,7 +688,7 @@ for opt, val in opts: if opt == "--help": - usage(sys.stdout) + _usage(sys.stdout) sys.exit(0) if opt == "--version": -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 27 16:38:14 2011 From: python-checkins at python.org (eric.araujo) Date: Wed, 27 Apr 2011 16:38:14 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): Merge 3.1 Message-ID: http://hg.python.org/cpython/rev/26c22aaf43a4 changeset: 69608:26c22aaf43a4 branch: 3.2 parent: 69607:226b7a551931 parent: 69603:acaec4d48023 user: ?ric Araujo date: Wed Apr 20 19:24:09 2011 +0200 summary: Merge 3.1 files: Doc/c-api/intro.rst | 3 +- Doc/documenting/markup.rst | 25 +++++++++++++-- Doc/library/dbm.rst | 4 +- Lib/dbm/__init__.py | 22 +++++++------ Lib/distutils/command/sdist.py | 23 ++++++++------ Lib/distutils/tests/test_register.py | 6 +- Lib/heapq.py | 6 +- 7 files changed, 55 insertions(+), 34 deletions(-) diff --git a/Doc/c-api/intro.rst b/Doc/c-api/intro.rst --- a/Doc/c-api/intro.rst +++ b/Doc/c-api/intro.rst @@ -511,13 +511,12 @@ module: builtins module: __main__ module: sys - module: exceptions triple: module; search; path single: path (in module sys) The basic initialization function is :c:func:`Py_Initialize`. This initializes the table of loaded modules, and creates the fundamental modules -:mod:`builtins`, :mod:`__main__`, :mod:`sys`, and :mod:`exceptions`. It also +:mod:`builtins`, :mod:`__main__`, and :mod:`sys`. It also initializes the module search path (``sys.path``). .. index:: single: PySys_SetArgvEx() diff --git a/Doc/documenting/markup.rst b/Doc/documenting/markup.rst --- a/Doc/documenting/markup.rst +++ b/Doc/documenting/markup.rst @@ -152,7 +152,7 @@ Describes global data in a module, including both variables and values used as "defined constants." Class and object attributes are not documented - using this environment. + using this directive. .. describe:: exception @@ -165,7 +165,7 @@ parameters, enclosing optional parameters in brackets. Default values can be given if it enhances clarity. For example:: - .. function:: Timer.repeat([repeat=3[, number=1000000]]) + .. function:: repeat([repeat=3[, number=1000000]]) Object methods are not documented using this directive. Bound object methods placed in the module namespace as part of the public interface of the module @@ -217,13 +217,30 @@ Describes an object data attribute. The description should include information about the type of the data to be expected and whether it may be - changed directly. + changed directly. This directive should be nested in a class directive, + like in this example:: + + .. class:: Spam + + Description of the class. + + .. data:: ham + + Description of the attribute. + + If is also possible to document an attribute outside of a class directive, + for example if the documentation for different attributes and methods is + split in multiple sections. The class name should then be included + explicitly:: + + .. data:: Spam.eggs .. describe:: method Describes an object method. The parameters should not include the ``self`` parameter. The description should include similar information to that - described for ``function``. + described for ``function``. This method should be nested in a class + method, like in the example above. .. describe:: decoratormethod diff --git a/Doc/library/dbm.rst b/Doc/library/dbm.rst --- a/Doc/library/dbm.rst +++ b/Doc/library/dbm.rst @@ -30,9 +30,9 @@ name, such as ``'dbm.ndbm'`` or ``'dbm.gnu'``. -.. function:: open(filename, flag='r', mode=0o666) +.. function:: open(file, flag='r', mode=0o666) - Open the database file *filename* and return a corresponding object. + Open the database file *file* and return a corresponding object. If the database file already exists, the :func:`whichdb` function is used to determine its type and the appropriate module is used; if it does not exist, diff --git a/Lib/dbm/__init__.py b/Lib/dbm/__init__.py --- a/Lib/dbm/__init__.py +++ b/Lib/dbm/__init__.py @@ -23,16 +23,8 @@ list = d.keys() # return a list of all existing keys (slow!) Future versions may change the order in which implementations are -tested for existence, add interfaces to other dbm-like +tested for existence, and add interfaces to other dbm-like implementations. - -The open function has an optional second argument. This can be 'r', -for read-only access, 'w', for read-write access of an existing -database, 'c' for read-write access to a new or existing database, and -'n' for read-write access to a new database. The default is 'r'. - -Note: 'r' and 'w' fail if the database doesn't exist; 'c' creates it -only if it doesn't exist; and 'n' always creates a new database. """ __all__ = ['open', 'whichdb', 'error'] @@ -53,7 +45,17 @@ error = (error, IOError) -def open(file, flag = 'r', mode = 0o666): +def open(file, flag='r', mode=0o666): + """Open or create database at path given by *file*. + + Optional argument *flag* can be 'r' (default) for read-only access, 'w' + for read-write access of an existing database, 'c' for read-write access + to a new or existing database, and 'n' for read-write access to a new + database. + + Note: 'r' and 'w' fail if the database doesn't exist; 'c' creates it + only if it doesn't exist; and 'n' always creates a new database. + """ global _defaultmod if _defaultmod is None: for name in _names: diff --git a/Lib/distutils/command/sdist.py b/Lib/distutils/command/sdist.py --- a/Lib/distutils/command/sdist.py +++ b/Lib/distutils/command/sdist.py @@ -294,17 +294,20 @@ join_lines=1, lstrip_ws=1, rstrip_ws=1, collapse_join=1) - while True: - line = template.readline() - if line is None: # end of file - break + try: + while True: + line = template.readline() + if line is None: # end of file + break - try: - self.filelist.process_template_line(line) - except DistutilsTemplateError as msg: - self.warn("%s, line %d: %s" % (template.filename, - template.current_line, - msg)) + try: + self.filelist.process_template_line(line) + except DistutilsTemplateError as msg: + self.warn("%s, line %d: %s" % (template.filename, + template.current_line, + msg)) + finally: + template.close() def prune_file_list(self): """Prune off branches that might slip into the file list as created diff --git a/Lib/distutils/tests/test_register.py b/Lib/distutils/tests/test_register.py --- a/Lib/distutils/tests/test_register.py +++ b/Lib/distutils/tests/test_register.py @@ -137,7 +137,7 @@ # let's see what the server received : we should # have 2 similar requests - self.assertTrue(self.conn.reqs, 2) + self.assertEqual(len(self.conn.reqs), 2) req1 = dict(self.conn.reqs[0].headers) req2 = dict(self.conn.reqs[1].headers) @@ -169,7 +169,7 @@ del register_module.input # we should have send a request - self.assertTrue(self.conn.reqs, 1) + self.assertEqual(len(self.conn.reqs), 1) req = self.conn.reqs[0] headers = dict(req.headers) self.assertEqual(headers['Content-length'], '608') @@ -187,7 +187,7 @@ del register_module.input # we should have send a request - self.assertTrue(self.conn.reqs, 1) + self.assertEqual(len(self.conn.reqs), 1) req = self.conn.reqs[0] headers = dict(req.headers) self.assertEqual(headers['Content-length'], '290') diff --git a/Lib/heapq.py b/Lib/heapq.py --- a/Lib/heapq.py +++ b/Lib/heapq.py @@ -170,7 +170,7 @@ return item def heapify(x): - """Transform list into a heap, in-place, in O(len(heap)) time.""" + """Transform list into a heap, in-place, in O(len(x)) time.""" n = len(x) # Transform bottom-up. The largest index there's any point to looking at # is the largest with a child index in-range, so must have 2*i + 1 < n, @@ -360,7 +360,7 @@ return [min(chain(head, it))] return [min(chain(head, it), key=key)] - # When n>=size, it's faster to use sort() + # When n>=size, it's faster to use sorted() try: size = len(iterable) except (TypeError, AttributeError): @@ -398,7 +398,7 @@ return [max(chain(head, it))] return [max(chain(head, it), key=key)] - # When n>=size, it's faster to use sort() + # When n>=size, it's faster to use sorted() try: size = len(iterable) except (TypeError, AttributeError): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 27 16:38:19 2011 From: python-checkins at python.org (eric.araujo) Date: Wed, 27 Apr 2011 16:38:19 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge 3.2 Message-ID: http://hg.python.org/cpython/rev/933494a3b705 changeset: 69609:933494a3b705 parent: 69440:253f8623ea0b parent: 69608:26c22aaf43a4 user: ?ric Araujo date: Wed Apr 20 20:22:57 2011 +0200 summary: Merge 3.2 files: Doc/c-api/intro.rst | 3 +- Doc/documenting/markup.rst | 25 +++++++++++++-- Doc/library/dbm.rst | 4 +- Lib/ast.py | 4 +- Lib/dbm/__init__.py | 22 +++++++------ Lib/distutils/command/sdist.py | 23 ++++++++------ Lib/distutils/tests/test_register.py | 6 +- Lib/heapq.py | 6 +- Lib/sysconfig.py | 1 - Lib/trace.py | 2 +- 10 files changed, 58 insertions(+), 38 deletions(-) diff --git a/Doc/c-api/intro.rst b/Doc/c-api/intro.rst --- a/Doc/c-api/intro.rst +++ b/Doc/c-api/intro.rst @@ -511,13 +511,12 @@ module: builtins module: __main__ module: sys - module: exceptions triple: module; search; path single: path (in module sys) The basic initialization function is :c:func:`Py_Initialize`. This initializes the table of loaded modules, and creates the fundamental modules -:mod:`builtins`, :mod:`__main__`, :mod:`sys`, and :mod:`exceptions`. It also +:mod:`builtins`, :mod:`__main__`, and :mod:`sys`. It also initializes the module search path (``sys.path``). .. index:: single: PySys_SetArgvEx() diff --git a/Doc/documenting/markup.rst b/Doc/documenting/markup.rst --- a/Doc/documenting/markup.rst +++ b/Doc/documenting/markup.rst @@ -152,7 +152,7 @@ Describes global data in a module, including both variables and values used as "defined constants." Class and object attributes are not documented - using this environment. + using this directive. .. describe:: exception @@ -165,7 +165,7 @@ parameters, enclosing optional parameters in brackets. Default values can be given if it enhances clarity. For example:: - .. function:: Timer.repeat([repeat=3[, number=1000000]]) + .. function:: repeat([repeat=3[, number=1000000]]) Object methods are not documented using this directive. Bound object methods placed in the module namespace as part of the public interface of the module @@ -217,13 +217,30 @@ Describes an object data attribute. The description should include information about the type of the data to be expected and whether it may be - changed directly. + changed directly. This directive should be nested in a class directive, + like in this example:: + + .. class:: Spam + + Description of the class. + + .. data:: ham + + Description of the attribute. + + If is also possible to document an attribute outside of a class directive, + for example if the documentation for different attributes and methods is + split in multiple sections. The class name should then be included + explicitly:: + + .. data:: Spam.eggs .. describe:: method Describes an object method. The parameters should not include the ``self`` parameter. The description should include similar information to that - described for ``function``. + described for ``function``. This method should be nested in a class + method, like in the example above. .. describe:: decoratormethod diff --git a/Doc/library/dbm.rst b/Doc/library/dbm.rst --- a/Doc/library/dbm.rst +++ b/Doc/library/dbm.rst @@ -30,9 +30,9 @@ name, such as ``'dbm.ndbm'`` or ``'dbm.gnu'``. -.. function:: open(filename, flag='r', mode=0o666) +.. function:: open(file, flag='r', mode=0o666) - Open the database file *filename* and return a corresponding object. + Open the database file *file* and return a corresponding object. If the database file already exists, the :func:`whichdb` function is used to determine its type and the appropriate module is used; if it does not exist, diff --git a/Lib/ast.py b/Lib/ast.py --- a/Lib/ast.py +++ b/Lib/ast.py @@ -40,8 +40,8 @@ """ Safely evaluate an expression node or a string containing a Python expression. The string or node provided may only consist of the following - Python literal structures: strings, numbers, tuples, lists, dicts, booleans, - and None. + Python literal structures: strings, bytes, numbers, tuples, lists, dicts, + sets, booleans, and None. """ _safe_names = {'None': None, 'True': True, 'False': False} if isinstance(node_or_string, str): diff --git a/Lib/dbm/__init__.py b/Lib/dbm/__init__.py --- a/Lib/dbm/__init__.py +++ b/Lib/dbm/__init__.py @@ -23,16 +23,8 @@ list = d.keys() # return a list of all existing keys (slow!) Future versions may change the order in which implementations are -tested for existence, add interfaces to other dbm-like +tested for existence, and add interfaces to other dbm-like implementations. - -The open function has an optional second argument. This can be 'r', -for read-only access, 'w', for read-write access of an existing -database, 'c' for read-write access to a new or existing database, and -'n' for read-write access to a new database. The default is 'r'. - -Note: 'r' and 'w' fail if the database doesn't exist; 'c' creates it -only if it doesn't exist; and 'n' always creates a new database. """ __all__ = ['open', 'whichdb', 'error'] @@ -53,7 +45,17 @@ error = (error, IOError) -def open(file, flag = 'r', mode = 0o666): +def open(file, flag='r', mode=0o666): + """Open or create database at path given by *file*. + + Optional argument *flag* can be 'r' (default) for read-only access, 'w' + for read-write access of an existing database, 'c' for read-write access + to a new or existing database, and 'n' for read-write access to a new + database. + + Note: 'r' and 'w' fail if the database doesn't exist; 'c' creates it + only if it doesn't exist; and 'n' always creates a new database. + """ global _defaultmod if _defaultmod is None: for name in _names: diff --git a/Lib/distutils/command/sdist.py b/Lib/distutils/command/sdist.py --- a/Lib/distutils/command/sdist.py +++ b/Lib/distutils/command/sdist.py @@ -294,17 +294,20 @@ join_lines=1, lstrip_ws=1, rstrip_ws=1, collapse_join=1) - while True: - line = template.readline() - if line is None: # end of file - break + try: + while True: + line = template.readline() + if line is None: # end of file + break - try: - self.filelist.process_template_line(line) - except DistutilsTemplateError as msg: - self.warn("%s, line %d: %s" % (template.filename, - template.current_line, - msg)) + try: + self.filelist.process_template_line(line) + except DistutilsTemplateError as msg: + self.warn("%s, line %d: %s" % (template.filename, + template.current_line, + msg)) + finally: + template.close() def prune_file_list(self): """Prune off branches that might slip into the file list as created diff --git a/Lib/distutils/tests/test_register.py b/Lib/distutils/tests/test_register.py --- a/Lib/distutils/tests/test_register.py +++ b/Lib/distutils/tests/test_register.py @@ -137,7 +137,7 @@ # let's see what the server received : we should # have 2 similar requests - self.assertTrue(self.conn.reqs, 2) + self.assertEqual(len(self.conn.reqs), 2) req1 = dict(self.conn.reqs[0].headers) req2 = dict(self.conn.reqs[1].headers) @@ -169,7 +169,7 @@ del register_module.input # we should have send a request - self.assertTrue(self.conn.reqs, 1) + self.assertEqual(len(self.conn.reqs), 1) req = self.conn.reqs[0] headers = dict(req.headers) self.assertEqual(headers['Content-length'], '608') @@ -187,7 +187,7 @@ del register_module.input # we should have send a request - self.assertTrue(self.conn.reqs, 1) + self.assertEqual(len(self.conn.reqs), 1) req = self.conn.reqs[0] headers = dict(req.headers) self.assertEqual(headers['Content-length'], '290') diff --git a/Lib/heapq.py b/Lib/heapq.py --- a/Lib/heapq.py +++ b/Lib/heapq.py @@ -170,7 +170,7 @@ return item def heapify(x): - """Transform list into a heap, in-place, in O(len(heap)) time.""" + """Transform list into a heap, in-place, in O(len(x)) time.""" n = len(x) # Transform bottom-up. The largest index there's any point to looking at # is the largest with a child index in-range, so must have 2*i + 1 < n, @@ -360,7 +360,7 @@ return [min(chain(head, it))] return [min(chain(head, it), key=key)] - # When n>=size, it's faster to use sort() + # When n>=size, it's faster to use sorted() try: size = len(iterable) except (TypeError, AttributeError): @@ -398,7 +398,7 @@ return [max(chain(head, it))] return [max(chain(head, it), key=key)] - # When n>=size, it's faster to use sort() + # When n>=size, it's faster to use sorted() try: size = len(iterable) except (TypeError, AttributeError): diff --git a/Lib/sysconfig.py b/Lib/sysconfig.py --- a/Lib/sysconfig.py +++ b/Lib/sysconfig.py @@ -694,7 +694,6 @@ m = re.search( r'ProductUserVisibleVersion\s*' + r'(.*?)', f.read()) - f.close() if m is not None: macrelease = '.'.join(m.group(1).split('.')[:2]) # else: fall back to the default behaviour diff --git a/Lib/trace.py b/Lib/trace.py --- a/Lib/trace.py +++ b/Lib/trace.py @@ -688,7 +688,7 @@ for opt, val in opts: if opt == "--help": - usage(sys.stdout) + _usage(sys.stdout) sys.exit(0) if opt == "--version": -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 27 16:38:21 2011 From: python-checkins at python.org (eric.araujo) Date: Wed, 27 Apr 2011 16:38:21 +0200 Subject: [Python-checkins] cpython (3.1): Add a space to make json doc a bit more readable Message-ID: http://hg.python.org/cpython/rev/ee48b38a93bc changeset: 69610:ee48b38a93bc branch: 3.1 parent: 69603:acaec4d48023 user: ?ric Araujo date: Thu Apr 21 02:37:41 2011 +0200 summary: Add a space to make json doc a bit more readable files: Doc/library/json.rst | 2 +- Lib/json/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/json.rst b/Doc/library/json.rst --- a/Doc/library/json.rst +++ b/Doc/library/json.rst @@ -34,7 +34,7 @@ Compact encoding:: >>> import json - >>> json.dumps([1,2,3,{'4': 5, '6': 7}], separators=(',',':')) + >>> json.dumps([1,2,3,{'4': 5, '6': 7}], separators=(',', ':')) '[1,2,3,{"4":5,"6":7}]' Pretty printing:: diff --git a/Lib/json/__init__.py b/Lib/json/__init__.py --- a/Lib/json/__init__.py +++ b/Lib/json/__init__.py @@ -31,7 +31,7 @@ Compact encoding:: >>> import json - >>> json.dumps([1,2,3,{'4': 5, '6': 7}], separators=(',',':')) + >>> json.dumps([1,2,3,{'4': 5, '6': 7}], separators=(',', ':')) '[1,2,3,{"4":5,"6":7}]' Pretty printing:: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 27 16:38:24 2011 From: python-checkins at python.org (eric.araujo) Date: Wed, 27 Apr 2011 16:38:24 +0200 Subject: [Python-checkins] cpython (3.1): Fix weird executable name Message-ID: http://hg.python.org/cpython/rev/6059e3b19249 changeset: 69611:6059e3b19249 branch: 3.1 user: ?ric Araujo date: Fri Apr 22 21:27:10 2011 +0200 summary: Fix weird executable name files: Doc/distutils/examples.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/distutils/examples.rst b/Doc/distutils/examples.rst --- a/Doc/distutils/examples.rst +++ b/Doc/distutils/examples.rst @@ -280,7 +280,7 @@ Where the long description is broken, ``check`` will be able to detect it by using the :mod:`docutils` parser:: - $ pythontrunk setup.py check --restructuredtext + $ python setup.py check --restructuredtext running check warning: check: Title underline too short. (line 2) warning: check: Could not finish the parsing. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 27 16:38:26 2011 From: python-checkins at python.org (eric.araujo) Date: Wed, 27 Apr 2011 16:38:26 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.1): Branch merge Message-ID: http://hg.python.org/cpython/rev/fab8a77a973a changeset: 69612:fab8a77a973a branch: 3.1 parent: 69499:b20d3f54366c parent: 69611:6059e3b19249 user: ?ric Araujo date: Sun Apr 24 02:34:11 2011 +0200 summary: Branch merge files: Doc/c-api/intro.rst | 3 +- Doc/distutils/examples.rst | 2 +- Doc/documenting/markup.rst | 25 +++++++++++++-- Doc/library/dbm.rst | 4 +- Doc/library/json.rst | 2 +- Lib/dbm/__init__.py | 22 +++++++------ Lib/distutils/command/sdist.py | 23 ++++++++------ Lib/distutils/tests/test_register.py | 6 +- Lib/heapq.py | 6 +- Lib/json/__init__.py | 2 +- 10 files changed, 58 insertions(+), 37 deletions(-) diff --git a/Doc/c-api/intro.rst b/Doc/c-api/intro.rst --- a/Doc/c-api/intro.rst +++ b/Doc/c-api/intro.rst @@ -511,13 +511,12 @@ module: builtins module: __main__ module: sys - module: exceptions triple: module; search; path single: path (in module sys) The basic initialization function is :cfunc:`Py_Initialize`. This initializes the table of loaded modules, and creates the fundamental modules -:mod:`builtins`, :mod:`__main__`, :mod:`sys`, and :mod:`exceptions`. It also +:mod:`builtins`, :mod:`__main__`, and :mod:`sys`. It also initializes the module search path (``sys.path``). .. index:: single: PySys_SetArgv() diff --git a/Doc/distutils/examples.rst b/Doc/distutils/examples.rst --- a/Doc/distutils/examples.rst +++ b/Doc/distutils/examples.rst @@ -280,7 +280,7 @@ Where the long description is broken, ``check`` will be able to detect it by using the :mod:`docutils` parser:: - $ pythontrunk setup.py check --restructuredtext + $ python setup.py check --restructuredtext running check warning: check: Title underline too short. (line 2) warning: check: Could not finish the parsing. diff --git a/Doc/documenting/markup.rst b/Doc/documenting/markup.rst --- a/Doc/documenting/markup.rst +++ b/Doc/documenting/markup.rst @@ -152,7 +152,7 @@ Describes global data in a module, including both variables and values used as "defined constants." Class and object attributes are not documented - using this environment. + using this directive. .. describe:: exception @@ -165,7 +165,7 @@ parameters, enclosing optional parameters in brackets. Default values can be given if it enhances clarity. For example:: - .. function:: Timer.repeat([repeat=3[, number=1000000]]) + .. function:: repeat([repeat=3[, number=1000000]]) Object methods are not documented using this directive. Bound object methods placed in the module namespace as part of the public interface of the module @@ -186,13 +186,30 @@ Describes an object data attribute. The description should include information about the type of the data to be expected and whether it may be - changed directly. + changed directly. This directive should be nested in a class directive, + like in this example:: + + .. class:: Spam + + Description of the class. + + .. data:: ham + + Description of the attribute. + + If is also possible to document an attribute outside of a class directive, + for example if the documentation for different attributes and methods is + split in multiple sections. The class name should then be included + explicitly:: + + .. data:: Spam.eggs .. describe:: method Describes an object method. The parameters should not include the ``self`` parameter. The description should include similar information to that - described for ``function``. + described for ``function``. This method should be nested in a class + method, like in the example above. .. describe:: opcode diff --git a/Doc/library/dbm.rst b/Doc/library/dbm.rst --- a/Doc/library/dbm.rst +++ b/Doc/library/dbm.rst @@ -30,9 +30,9 @@ name, such as ``'dbm.ndbm'`` or ``'dbm.gnu'``. -.. function:: open(filename, flag='r', mode=0o666) +.. function:: open(file, flag='r', mode=0o666) - Open the database file *filename* and return a corresponding object. + Open the database file *file* and return a corresponding object. If the database file already exists, the :func:`whichdb` function is used to determine its type and the appropriate module is used; if it does not exist, diff --git a/Doc/library/json.rst b/Doc/library/json.rst --- a/Doc/library/json.rst +++ b/Doc/library/json.rst @@ -34,7 +34,7 @@ Compact encoding:: >>> import json - >>> json.dumps([1,2,3,{'4': 5, '6': 7}], separators=(',',':')) + >>> json.dumps([1,2,3,{'4': 5, '6': 7}], separators=(',', ':')) '[1,2,3,{"4":5,"6":7}]' Pretty printing:: diff --git a/Lib/dbm/__init__.py b/Lib/dbm/__init__.py --- a/Lib/dbm/__init__.py +++ b/Lib/dbm/__init__.py @@ -24,16 +24,8 @@ list = d.keys() # return a list of all existing keys (slow!) Future versions may change the order in which implementations are -tested for existence, add interfaces to other dbm-like +tested for existence, and add interfaces to other dbm-like implementations. - -The open function has an optional second argument. This can be 'r', -for read-only access, 'w', for read-write access of an existing -database, 'c' for read-write access to a new or existing database, and -'n' for read-write access to a new database. The default is 'r'. - -Note: 'r' and 'w' fail if the database doesn't exist; 'c' creates it -only if it doesn't exist; and 'n' always creates a new database. """ __all__ = ['open', 'whichdb', 'error', 'error'] @@ -54,7 +46,17 @@ error = (error, IOError) -def open(file, flag = 'r', mode = 0o666): +def open(file, flag='r', mode=0o666): + """Open or create database at path given by *file*. + + Optional argument *flag* can be 'r' (default) for read-only access, 'w' + for read-write access of an existing database, 'c' for read-write access + to a new or existing database, and 'n' for read-write access to a new + database. + + Note: 'r' and 'w' fail if the database doesn't exist; 'c' creates it + only if it doesn't exist; and 'n' always creates a new database. + """ global _defaultmod if _defaultmod is None: for name in _names: diff --git a/Lib/distutils/command/sdist.py b/Lib/distutils/command/sdist.py --- a/Lib/distutils/command/sdist.py +++ b/Lib/distutils/command/sdist.py @@ -294,17 +294,20 @@ join_lines=1, lstrip_ws=1, rstrip_ws=1, collapse_join=1) - while True: - line = template.readline() - if line is None: # end of file - break + try: + while True: + line = template.readline() + if line is None: # end of file + break - try: - self.filelist.process_template_line(line) - except DistutilsTemplateError as msg: - self.warn("%s, line %d: %s" % (template.filename, - template.current_line, - msg)) + try: + self.filelist.process_template_line(line) + except DistutilsTemplateError as msg: + self.warn("%s, line %d: %s" % (template.filename, + template.current_line, + msg)) + finally: + template.close() def prune_file_list(self): """Prune off branches that might slip into the file list as created diff --git a/Lib/distutils/tests/test_register.py b/Lib/distutils/tests/test_register.py --- a/Lib/distutils/tests/test_register.py +++ b/Lib/distutils/tests/test_register.py @@ -137,7 +137,7 @@ # let's see what the server received : we should # have 2 similar requests - self.assertTrue(self.conn.reqs, 2) + self.assertEqual(len(self.conn.reqs), 2) req1 = dict(self.conn.reqs[0].headers) req2 = dict(self.conn.reqs[1].headers) @@ -169,7 +169,7 @@ del register_module.input # we should have send a request - self.assertTrue(self.conn.reqs, 1) + self.assertEqual(len(self.conn.reqs), 1) req = self.conn.reqs[0] headers = dict(req.headers) self.assertEqual(headers['Content-length'], '608') @@ -187,7 +187,7 @@ del register_module.input # we should have send a request - self.assertTrue(self.conn.reqs, 1) + self.assertEqual(len(self.conn.reqs), 1) req = self.conn.reqs[0] headers = dict(req.headers) self.assertEqual(headers['Content-length'], '290') diff --git a/Lib/heapq.py b/Lib/heapq.py --- a/Lib/heapq.py +++ b/Lib/heapq.py @@ -172,7 +172,7 @@ return item def heapify(x): - """Transform list into a heap, in-place, in O(len(heap)) time.""" + """Transform list into a heap, in-place, in O(len(x)) time.""" n = len(x) # Transform bottom-up. The largest index there's any point to looking at # is the largest with a child index in-range, so must have 2*i + 1 < n, @@ -363,7 +363,7 @@ return [min(chain(head, it))] return [min(chain(head, it), key=key)] - # When n>=size, it's faster to use sort() + # When n>=size, it's faster to use sorted() try: size = len(iterable) except (TypeError, AttributeError): @@ -401,7 +401,7 @@ return [max(chain(head, it))] return [max(chain(head, it), key=key)] - # When n>=size, it's faster to use sort() + # When n>=size, it's faster to use sorted() try: size = len(iterable) except (TypeError, AttributeError): diff --git a/Lib/json/__init__.py b/Lib/json/__init__.py --- a/Lib/json/__init__.py +++ b/Lib/json/__init__.py @@ -31,7 +31,7 @@ Compact encoding:: >>> import json - >>> json.dumps([1,2,3,{'4': 5, '6': 7}], separators=(',',':')) + >>> json.dumps([1,2,3,{'4': 5, '6': 7}], separators=(',', ':')) '[1,2,3,{"4":5,"6":7}]' Pretty printing:: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 27 16:38:30 2011 From: python-checkins at python.org (eric.araujo) Date: Wed, 27 Apr 2011 16:38:30 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> 3.2): Branch merge Message-ID: http://hg.python.org/cpython/rev/6665aadfc45b changeset: 69613:6665aadfc45b branch: 3.2 parent: 69526:9f1767d680ff parent: 69608:26c22aaf43a4 user: ?ric Araujo date: Sun Apr 24 02:39:43 2011 +0200 summary: Branch merge files: Doc/c-api/intro.rst | 3 +- Doc/documenting/markup.rst | 25 +++++++++++++-- Doc/library/dbm.rst | 4 +- Lib/ast.py | 4 +- Lib/dbm/__init__.py | 22 +++++++------ Lib/distutils/command/sdist.py | 23 ++++++++------ Lib/distutils/tests/test_register.py | 6 +- Lib/heapq.py | 6 +- Lib/sysconfig.py | 1 - Lib/trace.py | 2 +- 10 files changed, 58 insertions(+), 38 deletions(-) diff --git a/Doc/c-api/intro.rst b/Doc/c-api/intro.rst --- a/Doc/c-api/intro.rst +++ b/Doc/c-api/intro.rst @@ -511,13 +511,12 @@ module: builtins module: __main__ module: sys - module: exceptions triple: module; search; path single: path (in module sys) The basic initialization function is :c:func:`Py_Initialize`. This initializes the table of loaded modules, and creates the fundamental modules -:mod:`builtins`, :mod:`__main__`, :mod:`sys`, and :mod:`exceptions`. It also +:mod:`builtins`, :mod:`__main__`, and :mod:`sys`. It also initializes the module search path (``sys.path``). .. index:: single: PySys_SetArgvEx() diff --git a/Doc/documenting/markup.rst b/Doc/documenting/markup.rst --- a/Doc/documenting/markup.rst +++ b/Doc/documenting/markup.rst @@ -152,7 +152,7 @@ Describes global data in a module, including both variables and values used as "defined constants." Class and object attributes are not documented - using this environment. + using this directive. .. describe:: exception @@ -165,7 +165,7 @@ parameters, enclosing optional parameters in brackets. Default values can be given if it enhances clarity. For example:: - .. function:: Timer.repeat([repeat=3[, number=1000000]]) + .. function:: repeat([repeat=3[, number=1000000]]) Object methods are not documented using this directive. Bound object methods placed in the module namespace as part of the public interface of the module @@ -217,13 +217,30 @@ Describes an object data attribute. The description should include information about the type of the data to be expected and whether it may be - changed directly. + changed directly. This directive should be nested in a class directive, + like in this example:: + + .. class:: Spam + + Description of the class. + + .. data:: ham + + Description of the attribute. + + If is also possible to document an attribute outside of a class directive, + for example if the documentation for different attributes and methods is + split in multiple sections. The class name should then be included + explicitly:: + + .. data:: Spam.eggs .. describe:: method Describes an object method. The parameters should not include the ``self`` parameter. The description should include similar information to that - described for ``function``. + described for ``function``. This method should be nested in a class + method, like in the example above. .. describe:: decoratormethod diff --git a/Doc/library/dbm.rst b/Doc/library/dbm.rst --- a/Doc/library/dbm.rst +++ b/Doc/library/dbm.rst @@ -30,9 +30,9 @@ name, such as ``'dbm.ndbm'`` or ``'dbm.gnu'``. -.. function:: open(filename, flag='r', mode=0o666) +.. function:: open(file, flag='r', mode=0o666) - Open the database file *filename* and return a corresponding object. + Open the database file *file* and return a corresponding object. If the database file already exists, the :func:`whichdb` function is used to determine its type and the appropriate module is used; if it does not exist, diff --git a/Lib/ast.py b/Lib/ast.py --- a/Lib/ast.py +++ b/Lib/ast.py @@ -40,8 +40,8 @@ """ Safely evaluate an expression node or a string containing a Python expression. The string or node provided may only consist of the following - Python literal structures: strings, numbers, tuples, lists, dicts, booleans, - and None. + Python literal structures: strings, bytes, numbers, tuples, lists, dicts, + sets, booleans, and None. """ _safe_names = {'None': None, 'True': True, 'False': False} if isinstance(node_or_string, str): diff --git a/Lib/dbm/__init__.py b/Lib/dbm/__init__.py --- a/Lib/dbm/__init__.py +++ b/Lib/dbm/__init__.py @@ -23,16 +23,8 @@ list = d.keys() # return a list of all existing keys (slow!) Future versions may change the order in which implementations are -tested for existence, add interfaces to other dbm-like +tested for existence, and add interfaces to other dbm-like implementations. - -The open function has an optional second argument. This can be 'r', -for read-only access, 'w', for read-write access of an existing -database, 'c' for read-write access to a new or existing database, and -'n' for read-write access to a new database. The default is 'r'. - -Note: 'r' and 'w' fail if the database doesn't exist; 'c' creates it -only if it doesn't exist; and 'n' always creates a new database. """ __all__ = ['open', 'whichdb', 'error'] @@ -53,7 +45,17 @@ error = (error, IOError) -def open(file, flag = 'r', mode = 0o666): +def open(file, flag='r', mode=0o666): + """Open or create database at path given by *file*. + + Optional argument *flag* can be 'r' (default) for read-only access, 'w' + for read-write access of an existing database, 'c' for read-write access + to a new or existing database, and 'n' for read-write access to a new + database. + + Note: 'r' and 'w' fail if the database doesn't exist; 'c' creates it + only if it doesn't exist; and 'n' always creates a new database. + """ global _defaultmod if _defaultmod is None: for name in _names: diff --git a/Lib/distutils/command/sdist.py b/Lib/distutils/command/sdist.py --- a/Lib/distutils/command/sdist.py +++ b/Lib/distutils/command/sdist.py @@ -294,17 +294,20 @@ join_lines=1, lstrip_ws=1, rstrip_ws=1, collapse_join=1) - while True: - line = template.readline() - if line is None: # end of file - break + try: + while True: + line = template.readline() + if line is None: # end of file + break - try: - self.filelist.process_template_line(line) - except DistutilsTemplateError as msg: - self.warn("%s, line %d: %s" % (template.filename, - template.current_line, - msg)) + try: + self.filelist.process_template_line(line) + except DistutilsTemplateError as msg: + self.warn("%s, line %d: %s" % (template.filename, + template.current_line, + msg)) + finally: + template.close() def prune_file_list(self): """Prune off branches that might slip into the file list as created diff --git a/Lib/distutils/tests/test_register.py b/Lib/distutils/tests/test_register.py --- a/Lib/distutils/tests/test_register.py +++ b/Lib/distutils/tests/test_register.py @@ -137,7 +137,7 @@ # let's see what the server received : we should # have 2 similar requests - self.assertTrue(self.conn.reqs, 2) + self.assertEqual(len(self.conn.reqs), 2) req1 = dict(self.conn.reqs[0].headers) req2 = dict(self.conn.reqs[1].headers) @@ -169,7 +169,7 @@ del register_module.input # we should have send a request - self.assertTrue(self.conn.reqs, 1) + self.assertEqual(len(self.conn.reqs), 1) req = self.conn.reqs[0] headers = dict(req.headers) self.assertEqual(headers['Content-length'], '608') @@ -187,7 +187,7 @@ del register_module.input # we should have send a request - self.assertTrue(self.conn.reqs, 1) + self.assertEqual(len(self.conn.reqs), 1) req = self.conn.reqs[0] headers = dict(req.headers) self.assertEqual(headers['Content-length'], '290') diff --git a/Lib/heapq.py b/Lib/heapq.py --- a/Lib/heapq.py +++ b/Lib/heapq.py @@ -170,7 +170,7 @@ return item def heapify(x): - """Transform list into a heap, in-place, in O(len(heap)) time.""" + """Transform list into a heap, in-place, in O(len(x)) time.""" n = len(x) # Transform bottom-up. The largest index there's any point to looking at # is the largest with a child index in-range, so must have 2*i + 1 < n, @@ -360,7 +360,7 @@ return [min(chain(head, it))] return [min(chain(head, it), key=key)] - # When n>=size, it's faster to use sort() + # When n>=size, it's faster to use sorted() try: size = len(iterable) except (TypeError, AttributeError): @@ -398,7 +398,7 @@ return [max(chain(head, it))] return [max(chain(head, it), key=key)] - # When n>=size, it's faster to use sort() + # When n>=size, it's faster to use sorted() try: size = len(iterable) except (TypeError, AttributeError): diff --git a/Lib/sysconfig.py b/Lib/sysconfig.py --- a/Lib/sysconfig.py +++ b/Lib/sysconfig.py @@ -694,7 +694,6 @@ m = re.search( r'ProductUserVisibleVersion\s*' + r'(.*?)', f.read()) - f.close() if m is not None: macrelease = '.'.join(m.group(1).split('.')[:2]) # else: fall back to the default behaviour diff --git a/Lib/trace.py b/Lib/trace.py --- a/Lib/trace.py +++ b/Lib/trace.py @@ -688,7 +688,7 @@ for opt, val in opts: if opt == "--help": - usage(sys.stdout) + _usage(sys.stdout) sys.exit(0) if opt == "--version": -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 27 16:38:32 2011 From: python-checkins at python.org (eric.araujo) Date: Wed, 27 Apr 2011 16:38:32 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): Merge 3.1 Message-ID: http://hg.python.org/cpython/rev/2aaca67ad209 changeset: 69614:2aaca67ad209 branch: 3.2 parent: 69613:6665aadfc45b parent: 69612:fab8a77a973a user: ?ric Araujo date: Sun Apr 24 02:42:52 2011 +0200 summary: Merge 3.1 files: Doc/distutils/examples.rst | 2 +- Doc/library/json.rst | 2 +- Lib/json/__init__.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/distutils/examples.rst b/Doc/distutils/examples.rst --- a/Doc/distutils/examples.rst +++ b/Doc/distutils/examples.rst @@ -279,7 +279,7 @@ Where the long description is broken, ``check`` will be able to detect it by using the :mod:`docutils` parser:: - $ pythontrunk setup.py check --restructuredtext + $ python setup.py check --restructuredtext running check warning: check: Title underline too short. (line 2) warning: check: Could not finish the parsing. diff --git a/Doc/library/json.rst b/Doc/library/json.rst --- a/Doc/library/json.rst +++ b/Doc/library/json.rst @@ -34,7 +34,7 @@ Compact encoding:: >>> import json - >>> json.dumps([1,2,3,{'4': 5, '6': 7}], separators=(',',':')) + >>> json.dumps([1,2,3,{'4': 5, '6': 7}], separators=(',', ':')) '[1,2,3,{"4":5,"6":7}]' Pretty printing:: diff --git a/Lib/json/__init__.py b/Lib/json/__init__.py --- a/Lib/json/__init__.py +++ b/Lib/json/__init__.py @@ -31,7 +31,7 @@ Compact encoding:: >>> import json - >>> json.dumps([1,2,3,{'4': 5, '6': 7}], separators=(',',':')) + >>> json.dumps([1,2,3,{'4': 5, '6': 7}], separators=(',', ':')) '[1,2,3,{"4":5,"6":7}]' Pretty printing:: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 27 16:38:35 2011 From: python-checkins at python.org (eric.araujo) Date: Wed, 27 Apr 2011 16:38:35 +0200 Subject: [Python-checkins] cpython (3.2): Fix indentation Message-ID: http://hg.python.org/cpython/rev/8d4f27590a3e changeset: 69615:8d4f27590a3e branch: 3.2 user: ?ric Araujo date: Sun Apr 24 02:44:39 2011 +0200 summary: Fix indentation files: Doc/library/runpy.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/runpy.rst b/Doc/library/runpy.rst --- a/Doc/library/runpy.rst +++ b/Doc/library/runpy.rst @@ -49,7 +49,7 @@ loader does not make filename information available, this variable is set to :const:`None`. - ``__cached__`` will be set to ``None``. + ``__cached__`` will be set to ``None``. ``__loader__`` is set to the :pep:`302` module loader used to retrieve the code for the module (This loader may be a wrapper around the standard -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 27 16:38:41 2011 From: python-checkins at python.org (eric.araujo) Date: Wed, 27 Apr 2011 16:38:41 +0200 Subject: [Python-checkins] cpython (merge default -> default): Branch merge Message-ID: http://hg.python.org/cpython/rev/52d0aeb96864 changeset: 69616:52d0aeb96864 parent: 69528:fecf9e6d7630 parent: 69609:933494a3b705 user: ?ric Araujo date: Sun Apr 24 02:47:37 2011 +0200 summary: Branch merge files: Doc/c-api/intro.rst | 3 +- Doc/documenting/markup.rst | 25 +++++++++++++-- Doc/library/dbm.rst | 4 +- Lib/ast.py | 4 +- Lib/dbm/__init__.py | 22 +++++++------ Lib/distutils/command/sdist.py | 23 ++++++++------ Lib/distutils/tests/test_register.py | 6 +- Lib/heapq.py | 6 +- Lib/sysconfig.py | 1 - Lib/trace.py | 2 +- 10 files changed, 58 insertions(+), 38 deletions(-) diff --git a/Doc/c-api/intro.rst b/Doc/c-api/intro.rst --- a/Doc/c-api/intro.rst +++ b/Doc/c-api/intro.rst @@ -511,13 +511,12 @@ module: builtins module: __main__ module: sys - module: exceptions triple: module; search; path single: path (in module sys) The basic initialization function is :c:func:`Py_Initialize`. This initializes the table of loaded modules, and creates the fundamental modules -:mod:`builtins`, :mod:`__main__`, :mod:`sys`, and :mod:`exceptions`. It also +:mod:`builtins`, :mod:`__main__`, and :mod:`sys`. It also initializes the module search path (``sys.path``). .. index:: single: PySys_SetArgvEx() diff --git a/Doc/documenting/markup.rst b/Doc/documenting/markup.rst --- a/Doc/documenting/markup.rst +++ b/Doc/documenting/markup.rst @@ -152,7 +152,7 @@ Describes global data in a module, including both variables and values used as "defined constants." Class and object attributes are not documented - using this environment. + using this directive. .. describe:: exception @@ -165,7 +165,7 @@ parameters, enclosing optional parameters in brackets. Default values can be given if it enhances clarity. For example:: - .. function:: Timer.repeat([repeat=3[, number=1000000]]) + .. function:: repeat([repeat=3[, number=1000000]]) Object methods are not documented using this directive. Bound object methods placed in the module namespace as part of the public interface of the module @@ -217,13 +217,30 @@ Describes an object data attribute. The description should include information about the type of the data to be expected and whether it may be - changed directly. + changed directly. This directive should be nested in a class directive, + like in this example:: + + .. class:: Spam + + Description of the class. + + .. data:: ham + + Description of the attribute. + + If is also possible to document an attribute outside of a class directive, + for example if the documentation for different attributes and methods is + split in multiple sections. The class name should then be included + explicitly:: + + .. data:: Spam.eggs .. describe:: method Describes an object method. The parameters should not include the ``self`` parameter. The description should include similar information to that - described for ``function``. + described for ``function``. This method should be nested in a class + method, like in the example above. .. describe:: decoratormethod diff --git a/Doc/library/dbm.rst b/Doc/library/dbm.rst --- a/Doc/library/dbm.rst +++ b/Doc/library/dbm.rst @@ -30,9 +30,9 @@ name, such as ``'dbm.ndbm'`` or ``'dbm.gnu'``. -.. function:: open(filename, flag='r', mode=0o666) +.. function:: open(file, flag='r', mode=0o666) - Open the database file *filename* and return a corresponding object. + Open the database file *file* and return a corresponding object. If the database file already exists, the :func:`whichdb` function is used to determine its type and the appropriate module is used; if it does not exist, diff --git a/Lib/ast.py b/Lib/ast.py --- a/Lib/ast.py +++ b/Lib/ast.py @@ -40,8 +40,8 @@ """ Safely evaluate an expression node or a string containing a Python expression. The string or node provided may only consist of the following - Python literal structures: strings, numbers, tuples, lists, dicts, booleans, - and None. + Python literal structures: strings, bytes, numbers, tuples, lists, dicts, + sets, booleans, and None. """ _safe_names = {'None': None, 'True': True, 'False': False} if isinstance(node_or_string, str): diff --git a/Lib/dbm/__init__.py b/Lib/dbm/__init__.py --- a/Lib/dbm/__init__.py +++ b/Lib/dbm/__init__.py @@ -23,16 +23,8 @@ list = d.keys() # return a list of all existing keys (slow!) Future versions may change the order in which implementations are -tested for existence, add interfaces to other dbm-like +tested for existence, and add interfaces to other dbm-like implementations. - -The open function has an optional second argument. This can be 'r', -for read-only access, 'w', for read-write access of an existing -database, 'c' for read-write access to a new or existing database, and -'n' for read-write access to a new database. The default is 'r'. - -Note: 'r' and 'w' fail if the database doesn't exist; 'c' creates it -only if it doesn't exist; and 'n' always creates a new database. """ __all__ = ['open', 'whichdb', 'error'] @@ -53,7 +45,17 @@ error = (error, IOError) -def open(file, flag = 'r', mode = 0o666): +def open(file, flag='r', mode=0o666): + """Open or create database at path given by *file*. + + Optional argument *flag* can be 'r' (default) for read-only access, 'w' + for read-write access of an existing database, 'c' for read-write access + to a new or existing database, and 'n' for read-write access to a new + database. + + Note: 'r' and 'w' fail if the database doesn't exist; 'c' creates it + only if it doesn't exist; and 'n' always creates a new database. + """ global _defaultmod if _defaultmod is None: for name in _names: diff --git a/Lib/distutils/command/sdist.py b/Lib/distutils/command/sdist.py --- a/Lib/distutils/command/sdist.py +++ b/Lib/distutils/command/sdist.py @@ -294,17 +294,20 @@ join_lines=1, lstrip_ws=1, rstrip_ws=1, collapse_join=1) - while True: - line = template.readline() - if line is None: # end of file - break + try: + while True: + line = template.readline() + if line is None: # end of file + break - try: - self.filelist.process_template_line(line) - except DistutilsTemplateError as msg: - self.warn("%s, line %d: %s" % (template.filename, - template.current_line, - msg)) + try: + self.filelist.process_template_line(line) + except DistutilsTemplateError as msg: + self.warn("%s, line %d: %s" % (template.filename, + template.current_line, + msg)) + finally: + template.close() def prune_file_list(self): """Prune off branches that might slip into the file list as created diff --git a/Lib/distutils/tests/test_register.py b/Lib/distutils/tests/test_register.py --- a/Lib/distutils/tests/test_register.py +++ b/Lib/distutils/tests/test_register.py @@ -137,7 +137,7 @@ # let's see what the server received : we should # have 2 similar requests - self.assertTrue(self.conn.reqs, 2) + self.assertEqual(len(self.conn.reqs), 2) req1 = dict(self.conn.reqs[0].headers) req2 = dict(self.conn.reqs[1].headers) @@ -169,7 +169,7 @@ del register_module.input # we should have send a request - self.assertTrue(self.conn.reqs, 1) + self.assertEqual(len(self.conn.reqs), 1) req = self.conn.reqs[0] headers = dict(req.headers) self.assertEqual(headers['Content-length'], '608') @@ -187,7 +187,7 @@ del register_module.input # we should have send a request - self.assertTrue(self.conn.reqs, 1) + self.assertEqual(len(self.conn.reqs), 1) req = self.conn.reqs[0] headers = dict(req.headers) self.assertEqual(headers['Content-length'], '290') diff --git a/Lib/heapq.py b/Lib/heapq.py --- a/Lib/heapq.py +++ b/Lib/heapq.py @@ -170,7 +170,7 @@ return item def heapify(x): - """Transform list into a heap, in-place, in O(len(heap)) time.""" + """Transform list into a heap, in-place, in O(len(x)) time.""" n = len(x) # Transform bottom-up. The largest index there's any point to looking at # is the largest with a child index in-range, so must have 2*i + 1 < n, @@ -360,7 +360,7 @@ return [min(chain(head, it))] return [min(chain(head, it), key=key)] - # When n>=size, it's faster to use sort() + # When n>=size, it's faster to use sorted() try: size = len(iterable) except (TypeError, AttributeError): @@ -398,7 +398,7 @@ return [max(chain(head, it))] return [max(chain(head, it), key=key)] - # When n>=size, it's faster to use sort() + # When n>=size, it's faster to use sorted() try: size = len(iterable) except (TypeError, AttributeError): diff --git a/Lib/sysconfig.py b/Lib/sysconfig.py --- a/Lib/sysconfig.py +++ b/Lib/sysconfig.py @@ -694,7 +694,6 @@ m = re.search( r'ProductUserVisibleVersion\s*' + r'(.*?)', f.read()) - f.close() if m is not None: macrelease = '.'.join(m.group(1).split('.')[:2]) # else: fall back to the default behaviour diff --git a/Lib/trace.py b/Lib/trace.py --- a/Lib/trace.py +++ b/Lib/trace.py @@ -688,7 +688,7 @@ for opt, val in opts: if opt == "--help": - usage(sys.stdout) + _usage(sys.stdout) sys.exit(0) if opt == "--version": -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 27 16:38:43 2011 From: python-checkins at python.org (eric.araujo) Date: Wed, 27 Apr 2011 16:38:43 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge 3.2 Message-ID: http://hg.python.org/cpython/rev/73ac0477288e changeset: 69617:73ac0477288e parent: 69616:52d0aeb96864 parent: 69615:8d4f27590a3e user: ?ric Araujo date: Sun Apr 24 02:49:10 2011 +0200 summary: Merge 3.2 files: Doc/distutils/examples.rst | 2 +- Doc/library/json.rst | 2 +- Doc/library/runpy.rst | 2 +- Lib/json/__init__.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Doc/distutils/examples.rst b/Doc/distutils/examples.rst --- a/Doc/distutils/examples.rst +++ b/Doc/distutils/examples.rst @@ -279,7 +279,7 @@ Where the long description is broken, ``check`` will be able to detect it by using the :mod:`docutils` parser:: - $ pythontrunk setup.py check --restructuredtext + $ python setup.py check --restructuredtext running check warning: check: Title underline too short. (line 2) warning: check: Could not finish the parsing. diff --git a/Doc/library/json.rst b/Doc/library/json.rst --- a/Doc/library/json.rst +++ b/Doc/library/json.rst @@ -34,7 +34,7 @@ Compact encoding:: >>> import json - >>> json.dumps([1,2,3,{'4': 5, '6': 7}], separators=(',',':')) + >>> json.dumps([1,2,3,{'4': 5, '6': 7}], separators=(',', ':')) '[1,2,3,{"4":5,"6":7}]' Pretty printing:: diff --git a/Doc/library/runpy.rst b/Doc/library/runpy.rst --- a/Doc/library/runpy.rst +++ b/Doc/library/runpy.rst @@ -49,7 +49,7 @@ loader does not make filename information available, this variable is set to :const:`None`. - ``__cached__`` will be set to ``None``. + ``__cached__`` will be set to ``None``. ``__loader__`` is set to the :pep:`302` module loader used to retrieve the code for the module (This loader may be a wrapper around the standard diff --git a/Lib/json/__init__.py b/Lib/json/__init__.py --- a/Lib/json/__init__.py +++ b/Lib/json/__init__.py @@ -31,7 +31,7 @@ Compact encoding:: >>> import json - >>> json.dumps([1,2,3,{'4': 5, '6': 7}], separators=(',',':')) + >>> json.dumps([1,2,3,{'4': 5, '6': 7}], separators=(',', ':')) '[1,2,3,{"4":5,"6":7}]' Pretty printing:: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 27 16:38:45 2011 From: python-checkins at python.org (eric.araujo) Date: Wed, 27 Apr 2011 16:38:45 +0200 Subject: [Python-checkins] cpython (3.2): Remove unneeded backslashes Message-ID: http://hg.python.org/cpython/rev/f973b77522f6 changeset: 69618:f973b77522f6 branch: 3.2 parent: 69615:8d4f27590a3e user: ?ric Araujo date: Sun Apr 24 02:59:02 2011 +0200 summary: Remove unneeded backslashes files: Doc/library/collections.rst | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/collections.rst b/Doc/library/collections.rst --- a/Doc/library/collections.rst +++ b/Doc/library/collections.rst @@ -205,14 +205,14 @@ * `Bag class `_ in Smalltalk. - * Wikipedia entry for `Multisets `_\. + * Wikipedia entry for `Multisets `_. * `C++ multisets `_ tutorial with examples. * For mathematical operations on multisets and their use cases, see *Knuth, Donald. The Art of Computer Programming Volume II, - Section 4.6.3, Exercise 19*\. + Section 4.6.3, Exercise 19*. * To enumerate all distinct multisets of a given size over a given set of elements, see :func:`itertools.combinations_with_replacement`. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 27 16:38:50 2011 From: python-checkins at python.org (eric.araujo) Date: Wed, 27 Apr 2011 16:38:50 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Remove unneeded backslashes Message-ID: http://hg.python.org/cpython/rev/4fb93de88376 changeset: 69619:4fb93de88376 parent: 69617:73ac0477288e parent: 69618:f973b77522f6 user: ?ric Araujo date: Sun Apr 24 03:00:58 2011 +0200 summary: Remove unneeded backslashes files: Doc/library/collections.rst | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Doc/library/collections.rst b/Doc/library/collections.rst --- a/Doc/library/collections.rst +++ b/Doc/library/collections.rst @@ -134,7 +134,7 @@ * The `MultiContext class `_ in the Enthought `CodeTools package - `_\ has options to support + `_ has options to support writing to any mapping in the chain. * Django's `Context class @@ -150,7 +150,7 @@ any mapping in the chain. * A `greatly simplified read-only version of Chainmap - `_\. + `_. :class:`Counter` objects ------------------------ @@ -320,14 +320,14 @@ * `Bag class `_ in Smalltalk. - * Wikipedia entry for `Multisets `_\. + * Wikipedia entry for `Multisets `_. * `C++ multisets `_ tutorial with examples. * For mathematical operations on multisets and their use cases, see *Knuth, Donald. The Art of Computer Programming Volume II, - Section 4.6.3, Exercise 19*\. + Section 4.6.3, Exercise 19*. * To enumerate all distinct multisets of a given size over a given set of elements, see :func:`itertools.combinations_with_replacement`. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 27 16:38:53 2011 From: python-checkins at python.org (eric.araujo) Date: Wed, 27 Apr 2011 16:38:53 +0200 Subject: [Python-checkins] cpython: Add versionchanged for a364719e400a (#11591) Message-ID: http://hg.python.org/cpython/rev/9a1ca0062950 changeset: 69620:9a1ca0062950 user: ?ric Araujo date: Sun Apr 24 03:15:32 2011 +0200 summary: Add versionchanged for a364719e400a (#11591) files: Doc/library/site.rst | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-) diff --git a/Doc/library/site.rst b/Doc/library/site.rst --- a/Doc/library/site.rst +++ b/Doc/library/site.rst @@ -19,6 +19,10 @@ explicitly trigger the usual site-specific additions, call the :func:`site.main` function. +.. versionchanged:: 3.3 + Importing the module used to trigger paths manipulation even when using + :option:`-S`. + .. index:: pair: site-python; directory pair: site-packages; directory -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 27 16:38:56 2011 From: python-checkins at python.org (eric.araujo) Date: Wed, 27 Apr 2011 16:38:56 +0200 Subject: [Python-checkins] cpython: Add versionchanged for c19752ea037f (#10998) Message-ID: http://hg.python.org/cpython/rev/f9e2b2b17e58 changeset: 69622:f9e2b2b17e58 parent: 69620:9a1ca0062950 user: ?ric Araujo date: Sun Apr 24 04:37:00 2011 +0200 summary: Add versionchanged for c19752ea037f (#10998) files: Doc/library/sys.rst | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -246,6 +246,9 @@ .. versionchanged:: 3.2 Added ``quiet`` attribute for the new :option:`-q` flag. + .. versionchanged:: 3.3 + Removed obsolete ``division_warning`` attribute. + .. data:: float_info -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 27 16:38:58 2011 From: python-checkins at python.org (eric.araujo) Date: Wed, 27 Apr 2011 16:38:58 +0200 Subject: [Python-checkins] cpython (merge default -> default): Branch merge Message-ID: http://hg.python.org/cpython/rev/95f9c2d6a1e7 changeset: 69623:95f9c2d6a1e7 parent: 69595:4e7151c972a2 parent: 69622:f9e2b2b17e58 user: ?ric Araujo date: Wed Apr 27 16:28:50 2011 +0200 summary: Branch merge files: Doc/c-api/intro.rst | 3 +- Doc/distutils/examples.rst | 2 +- Doc/documenting/markup.rst | 25 +++++++++++++-- Doc/library/collections.rst | 8 ++-- Doc/library/dbm.rst | 4 +- Doc/library/json.rst | 2 +- Doc/library/runpy.rst | 2 +- Doc/library/site.rst | 4 ++ Doc/library/sys.rst | 3 + Lib/ast.py | 4 +- Lib/dbm/__init__.py | 22 +++++++------ Lib/distutils/command/sdist.py | 23 ++++++++------ Lib/distutils/tests/test_register.py | 6 +- Lib/heapq.py | 6 +- Lib/json/__init__.py | 2 +- Lib/sysconfig.py | 1 - Lib/trace.py | 2 +- 17 files changed, 73 insertions(+), 46 deletions(-) diff --git a/Doc/c-api/intro.rst b/Doc/c-api/intro.rst --- a/Doc/c-api/intro.rst +++ b/Doc/c-api/intro.rst @@ -511,13 +511,12 @@ module: builtins module: __main__ module: sys - module: exceptions triple: module; search; path single: path (in module sys) The basic initialization function is :c:func:`Py_Initialize`. This initializes the table of loaded modules, and creates the fundamental modules -:mod:`builtins`, :mod:`__main__`, :mod:`sys`, and :mod:`exceptions`. It also +:mod:`builtins`, :mod:`__main__`, and :mod:`sys`. It also initializes the module search path (``sys.path``). .. index:: single: PySys_SetArgvEx() diff --git a/Doc/distutils/examples.rst b/Doc/distutils/examples.rst --- a/Doc/distutils/examples.rst +++ b/Doc/distutils/examples.rst @@ -279,7 +279,7 @@ Where the long description is broken, ``check`` will be able to detect it by using the :mod:`docutils` parser:: - $ pythontrunk setup.py check --restructuredtext + $ python setup.py check --restructuredtext running check warning: check: Title underline too short. (line 2) warning: check: Could not finish the parsing. diff --git a/Doc/documenting/markup.rst b/Doc/documenting/markup.rst --- a/Doc/documenting/markup.rst +++ b/Doc/documenting/markup.rst @@ -152,7 +152,7 @@ Describes global data in a module, including both variables and values used as "defined constants." Class and object attributes are not documented - using this environment. + using this directive. .. describe:: exception @@ -165,7 +165,7 @@ parameters, enclosing optional parameters in brackets. Default values can be given if it enhances clarity. For example:: - .. function:: Timer.repeat([repeat=3[, number=1000000]]) + .. function:: repeat([repeat=3[, number=1000000]]) Object methods are not documented using this directive. Bound object methods placed in the module namespace as part of the public interface of the module @@ -217,13 +217,30 @@ Describes an object data attribute. The description should include information about the type of the data to be expected and whether it may be - changed directly. + changed directly. This directive should be nested in a class directive, + like in this example:: + + .. class:: Spam + + Description of the class. + + .. data:: ham + + Description of the attribute. + + If is also possible to document an attribute outside of a class directive, + for example if the documentation for different attributes and methods is + split in multiple sections. The class name should then be included + explicitly:: + + .. data:: Spam.eggs .. describe:: method Describes an object method. The parameters should not include the ``self`` parameter. The description should include similar information to that - described for ``function``. + described for ``function``. This method should be nested in a class + method, like in the example above. .. describe:: decoratormethod diff --git a/Doc/library/collections.rst b/Doc/library/collections.rst --- a/Doc/library/collections.rst +++ b/Doc/library/collections.rst @@ -134,7 +134,7 @@ * The `MultiContext class `_ in the Enthought `CodeTools package - `_\ has options to support + `_ has options to support writing to any mapping in the chain. * Django's `Context class @@ -150,7 +150,7 @@ any mapping in the chain. * A `greatly simplified read-only version of Chainmap - `_\. + `_. :class:`Counter` objects ------------------------ @@ -320,14 +320,14 @@ * `Bag class `_ in Smalltalk. - * Wikipedia entry for `Multisets `_\. + * Wikipedia entry for `Multisets `_. * `C++ multisets `_ tutorial with examples. * For mathematical operations on multisets and their use cases, see *Knuth, Donald. The Art of Computer Programming Volume II, - Section 4.6.3, Exercise 19*\. + Section 4.6.3, Exercise 19*. * To enumerate all distinct multisets of a given size over a given set of elements, see :func:`itertools.combinations_with_replacement`. diff --git a/Doc/library/dbm.rst b/Doc/library/dbm.rst --- a/Doc/library/dbm.rst +++ b/Doc/library/dbm.rst @@ -30,9 +30,9 @@ name, such as ``'dbm.ndbm'`` or ``'dbm.gnu'``. -.. function:: open(filename, flag='r', mode=0o666) +.. function:: open(file, flag='r', mode=0o666) - Open the database file *filename* and return a corresponding object. + Open the database file *file* and return a corresponding object. If the database file already exists, the :func:`whichdb` function is used to determine its type and the appropriate module is used; if it does not exist, diff --git a/Doc/library/json.rst b/Doc/library/json.rst --- a/Doc/library/json.rst +++ b/Doc/library/json.rst @@ -34,7 +34,7 @@ Compact encoding:: >>> import json - >>> json.dumps([1,2,3,{'4': 5, '6': 7}], separators=(',',':')) + >>> json.dumps([1,2,3,{'4': 5, '6': 7}], separators=(',', ':')) '[1,2,3,{"4":5,"6":7}]' Pretty printing:: diff --git a/Doc/library/runpy.rst b/Doc/library/runpy.rst --- a/Doc/library/runpy.rst +++ b/Doc/library/runpy.rst @@ -49,7 +49,7 @@ loader does not make filename information available, this variable is set to :const:`None`. - ``__cached__`` will be set to ``None``. + ``__cached__`` will be set to ``None``. ``__loader__`` is set to the :pep:`302` module loader used to retrieve the code for the module (This loader may be a wrapper around the standard diff --git a/Doc/library/site.rst b/Doc/library/site.rst --- a/Doc/library/site.rst +++ b/Doc/library/site.rst @@ -19,6 +19,10 @@ explicitly trigger the usual site-specific additions, call the :func:`site.main` function. +.. versionchanged:: 3.3 + Importing the module used to trigger paths manipulation even when using + :option:`-S`. + .. index:: pair: site-python; directory pair: site-packages; directory diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -246,6 +246,9 @@ .. versionchanged:: 3.2 Added ``quiet`` attribute for the new :option:`-q` flag. + .. versionchanged:: 3.3 + Removed obsolete ``division_warning`` attribute. + .. data:: float_info diff --git a/Lib/ast.py b/Lib/ast.py --- a/Lib/ast.py +++ b/Lib/ast.py @@ -40,8 +40,8 @@ """ Safely evaluate an expression node or a string containing a Python expression. The string or node provided may only consist of the following - Python literal structures: strings, numbers, tuples, lists, dicts, booleans, - and None. + Python literal structures: strings, bytes, numbers, tuples, lists, dicts, + sets, booleans, and None. """ _safe_names = {'None': None, 'True': True, 'False': False} if isinstance(node_or_string, str): diff --git a/Lib/dbm/__init__.py b/Lib/dbm/__init__.py --- a/Lib/dbm/__init__.py +++ b/Lib/dbm/__init__.py @@ -23,16 +23,8 @@ list = d.keys() # return a list of all existing keys (slow!) Future versions may change the order in which implementations are -tested for existence, add interfaces to other dbm-like +tested for existence, and add interfaces to other dbm-like implementations. - -The open function has an optional second argument. This can be 'r', -for read-only access, 'w', for read-write access of an existing -database, 'c' for read-write access to a new or existing database, and -'n' for read-write access to a new database. The default is 'r'. - -Note: 'r' and 'w' fail if the database doesn't exist; 'c' creates it -only if it doesn't exist; and 'n' always creates a new database. """ __all__ = ['open', 'whichdb', 'error'] @@ -53,7 +45,17 @@ error = (error, IOError) -def open(file, flag = 'r', mode = 0o666): +def open(file, flag='r', mode=0o666): + """Open or create database at path given by *file*. + + Optional argument *flag* can be 'r' (default) for read-only access, 'w' + for read-write access of an existing database, 'c' for read-write access + to a new or existing database, and 'n' for read-write access to a new + database. + + Note: 'r' and 'w' fail if the database doesn't exist; 'c' creates it + only if it doesn't exist; and 'n' always creates a new database. + """ global _defaultmod if _defaultmod is None: for name in _names: diff --git a/Lib/distutils/command/sdist.py b/Lib/distutils/command/sdist.py --- a/Lib/distutils/command/sdist.py +++ b/Lib/distutils/command/sdist.py @@ -294,17 +294,20 @@ join_lines=1, lstrip_ws=1, rstrip_ws=1, collapse_join=1) - while True: - line = template.readline() - if line is None: # end of file - break + try: + while True: + line = template.readline() + if line is None: # end of file + break - try: - self.filelist.process_template_line(line) - except DistutilsTemplateError as msg: - self.warn("%s, line %d: %s" % (template.filename, - template.current_line, - msg)) + try: + self.filelist.process_template_line(line) + except DistutilsTemplateError as msg: + self.warn("%s, line %d: %s" % (template.filename, + template.current_line, + msg)) + finally: + template.close() def prune_file_list(self): """Prune off branches that might slip into the file list as created diff --git a/Lib/distutils/tests/test_register.py b/Lib/distutils/tests/test_register.py --- a/Lib/distutils/tests/test_register.py +++ b/Lib/distutils/tests/test_register.py @@ -137,7 +137,7 @@ # let's see what the server received : we should # have 2 similar requests - self.assertTrue(self.conn.reqs, 2) + self.assertEqual(len(self.conn.reqs), 2) req1 = dict(self.conn.reqs[0].headers) req2 = dict(self.conn.reqs[1].headers) @@ -169,7 +169,7 @@ del register_module.input # we should have send a request - self.assertTrue(self.conn.reqs, 1) + self.assertEqual(len(self.conn.reqs), 1) req = self.conn.reqs[0] headers = dict(req.headers) self.assertEqual(headers['Content-length'], '608') @@ -187,7 +187,7 @@ del register_module.input # we should have send a request - self.assertTrue(self.conn.reqs, 1) + self.assertEqual(len(self.conn.reqs), 1) req = self.conn.reqs[0] headers = dict(req.headers) self.assertEqual(headers['Content-length'], '290') diff --git a/Lib/heapq.py b/Lib/heapq.py --- a/Lib/heapq.py +++ b/Lib/heapq.py @@ -170,7 +170,7 @@ return item def heapify(x): - """Transform list into a heap, in-place, in O(len(heap)) time.""" + """Transform list into a heap, in-place, in O(len(x)) time.""" n = len(x) # Transform bottom-up. The largest index there's any point to looking at # is the largest with a child index in-range, so must have 2*i + 1 < n, @@ -360,7 +360,7 @@ return [min(chain(head, it))] return [min(chain(head, it), key=key)] - # When n>=size, it's faster to use sort() + # When n>=size, it's faster to use sorted() try: size = len(iterable) except (TypeError, AttributeError): @@ -398,7 +398,7 @@ return [max(chain(head, it))] return [max(chain(head, it), key=key)] - # When n>=size, it's faster to use sort() + # When n>=size, it's faster to use sorted() try: size = len(iterable) except (TypeError, AttributeError): diff --git a/Lib/json/__init__.py b/Lib/json/__init__.py --- a/Lib/json/__init__.py +++ b/Lib/json/__init__.py @@ -31,7 +31,7 @@ Compact encoding:: >>> import json - >>> json.dumps([1,2,3,{'4': 5, '6': 7}], separators=(',',':')) + >>> json.dumps([1,2,3,{'4': 5, '6': 7}], separators=(',', ':')) '[1,2,3,{"4":5,"6":7}]' Pretty printing:: diff --git a/Lib/sysconfig.py b/Lib/sysconfig.py --- a/Lib/sysconfig.py +++ b/Lib/sysconfig.py @@ -694,7 +694,6 @@ m = re.search( r'ProductUserVisibleVersion\s*' + r'(.*?)', f.read()) - f.close() if m is not None: macrelease = '.'.join(m.group(1).split('.')[:2]) # else: fall back to the default behaviour diff --git a/Lib/trace.py b/Lib/trace.py --- a/Lib/trace.py +++ b/Lib/trace.py @@ -688,7 +688,7 @@ for opt, val in opts: if opt == "--help": - usage(sys.stdout) + _usage(sys.stdout) sys.exit(0) if opt == "--version": -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 27 16:39:04 2011 From: python-checkins at python.org (eric.araujo) Date: Wed, 27 Apr 2011 16:39:04 +0200 Subject: [Python-checkins] cpython (3.1): Remove obsolete/duplicate docstring Message-ID: http://hg.python.org/cpython/rev/a9437f31469b changeset: 69624:a9437f31469b branch: 3.1 parent: 69612:fab8a77a973a user: ?ric Araujo date: Sun Apr 24 17:10:30 2011 +0200 summary: Remove obsolete/duplicate docstring files: Lib/test/tracedmodules/__init__.py | 5 ----- 1 files changed, 0 insertions(+), 5 deletions(-) diff --git a/Lib/test/tracedmodules/__init__.py b/Lib/test/tracedmodules/__init__.py --- a/Lib/test/tracedmodules/__init__.py +++ b/Lib/test/tracedmodules/__init__.py @@ -2,8 +2,3 @@ that the exact location of functions in these modules is important, as trace.py takes the real line numbers into account. """ -"""This directory contains modules that help testing the trace.py module. Note -that the exact location of functions in these modules is important, as trace.py -takes the real line numbers into account. - -""" -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 27 16:39:06 2011 From: python-checkins at python.org (eric.araujo) Date: Wed, 27 Apr 2011 16:39:06 +0200 Subject: [Python-checkins] cpython (3.1): Change markup so that it creates a link Message-ID: http://hg.python.org/cpython/rev/5ee5d60b605d changeset: 69625:5ee5d60b605d branch: 3.1 user: ?ric Araujo date: Mon Apr 25 19:05:53 2011 +0200 summary: Change markup so that it creates a link files: Doc/library/wsgiref.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/wsgiref.rst b/Doc/library/wsgiref.rst --- a/Doc/library/wsgiref.rst +++ b/Doc/library/wsgiref.rst @@ -664,7 +664,7 @@ .. attribute:: BaseHandler.wsgi_file_wrapper A ``wsgi.file_wrapper`` factory, or ``None``. The default value of this - attribute is the :class:`FileWrapper` class from :mod:`wsgiref.util`. + attribute is the :class:`wsgiref.util.FileWrapper` class. .. method:: BaseHandler.sendfile() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 27 16:39:09 2011 From: python-checkins at python.org (eric.araujo) Date: Wed, 27 Apr 2011 16:39:09 +0200 Subject: [Python-checkins] cpython (3.1): Change markup so it generates a link Message-ID: http://hg.python.org/cpython/rev/3207b6df5b80 changeset: 69626:3207b6df5b80 branch: 3.1 user: ?ric Araujo date: Wed Apr 27 16:22:32 2011 +0200 summary: Change markup so it generates a link files: Doc/library/__future__.rst | 2 +- Doc/library/sys.rst | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/library/__future__.rst b/Doc/library/__future__.rst --- a/Doc/library/__future__.rst +++ b/Doc/library/__future__.rst @@ -26,7 +26,7 @@ where, normally, *OptionalRelease* is less than *MandatoryRelease*, and both are -5-tuples of the same form as ``sys.version_info``:: +5-tuples of the same form as :data:`sys.version_info`:: (PY_MAJOR_VERSION, # the 2 in 2.1.0a3; an int PY_MINOR_VERSION, # the 1; an int diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -447,8 +447,8 @@ This is called ``hexversion`` since it only really looks meaningful when viewed as the result of passing it to the built-in :func:`hex` function. The - ``version_info`` value may be used for a more human-friendly encoding of the - same information. + struct sequence :data:`sys.version_info` may be used for a more human-friendly + encoding of the same information. .. data:: int_info -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 27 16:39:11 2011 From: python-checkins at python.org (eric.araujo) Date: Wed, 27 Apr 2011 16:39:11 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.1): Branch merge Message-ID: http://hg.python.org/cpython/rev/aca7a3091c9b changeset: 69627:aca7a3091c9b branch: 3.1 parent: 69589:04e64f77c6c7 parent: 69626:3207b6df5b80 user: ?ric Araujo date: Wed Apr 27 16:23:56 2011 +0200 summary: Branch merge files: Doc/c-api/intro.rst | 3 +- Doc/distutils/examples.rst | 2 +- Doc/documenting/markup.rst | 25 +++++++++++++-- Doc/library/__future__.rst | 2 +- Doc/library/dbm.rst | 4 +- Doc/library/json.rst | 2 +- Doc/library/sys.rst | 4 +- Doc/library/wsgiref.rst | 2 +- Lib/dbm/__init__.py | 22 +++++++------ Lib/distutils/command/sdist.py | 23 ++++++++------ Lib/distutils/tests/test_register.py | 6 +- Lib/heapq.py | 6 +- Lib/json/__init__.py | 2 +- Lib/test/tracedmodules/__init__.py | 5 --- 14 files changed, 62 insertions(+), 46 deletions(-) diff --git a/Doc/c-api/intro.rst b/Doc/c-api/intro.rst --- a/Doc/c-api/intro.rst +++ b/Doc/c-api/intro.rst @@ -511,13 +511,12 @@ module: builtins module: __main__ module: sys - module: exceptions triple: module; search; path single: path (in module sys) The basic initialization function is :cfunc:`Py_Initialize`. This initializes the table of loaded modules, and creates the fundamental modules -:mod:`builtins`, :mod:`__main__`, :mod:`sys`, and :mod:`exceptions`. It also +:mod:`builtins`, :mod:`__main__`, and :mod:`sys`. It also initializes the module search path (``sys.path``). .. index:: single: PySys_SetArgv() diff --git a/Doc/distutils/examples.rst b/Doc/distutils/examples.rst --- a/Doc/distutils/examples.rst +++ b/Doc/distutils/examples.rst @@ -280,7 +280,7 @@ Where the long description is broken, ``check`` will be able to detect it by using the :mod:`docutils` parser:: - $ pythontrunk setup.py check --restructuredtext + $ python setup.py check --restructuredtext running check warning: check: Title underline too short. (line 2) warning: check: Could not finish the parsing. diff --git a/Doc/documenting/markup.rst b/Doc/documenting/markup.rst --- a/Doc/documenting/markup.rst +++ b/Doc/documenting/markup.rst @@ -152,7 +152,7 @@ Describes global data in a module, including both variables and values used as "defined constants." Class and object attributes are not documented - using this environment. + using this directive. .. describe:: exception @@ -165,7 +165,7 @@ parameters, enclosing optional parameters in brackets. Default values can be given if it enhances clarity. For example:: - .. function:: Timer.repeat([repeat=3[, number=1000000]]) + .. function:: repeat([repeat=3[, number=1000000]]) Object methods are not documented using this directive. Bound object methods placed in the module namespace as part of the public interface of the module @@ -186,13 +186,30 @@ Describes an object data attribute. The description should include information about the type of the data to be expected and whether it may be - changed directly. + changed directly. This directive should be nested in a class directive, + like in this example:: + + .. class:: Spam + + Description of the class. + + .. data:: ham + + Description of the attribute. + + If is also possible to document an attribute outside of a class directive, + for example if the documentation for different attributes and methods is + split in multiple sections. The class name should then be included + explicitly:: + + .. data:: Spam.eggs .. describe:: method Describes an object method. The parameters should not include the ``self`` parameter. The description should include similar information to that - described for ``function``. + described for ``function``. This method should be nested in a class + method, like in the example above. .. describe:: opcode diff --git a/Doc/library/__future__.rst b/Doc/library/__future__.rst --- a/Doc/library/__future__.rst +++ b/Doc/library/__future__.rst @@ -26,7 +26,7 @@ where, normally, *OptionalRelease* is less than *MandatoryRelease*, and both are -5-tuples of the same form as ``sys.version_info``:: +5-tuples of the same form as :data:`sys.version_info`:: (PY_MAJOR_VERSION, # the 2 in 2.1.0a3; an int PY_MINOR_VERSION, # the 1; an int diff --git a/Doc/library/dbm.rst b/Doc/library/dbm.rst --- a/Doc/library/dbm.rst +++ b/Doc/library/dbm.rst @@ -30,9 +30,9 @@ name, such as ``'dbm.ndbm'`` or ``'dbm.gnu'``. -.. function:: open(filename, flag='r', mode=0o666) +.. function:: open(file, flag='r', mode=0o666) - Open the database file *filename* and return a corresponding object. + Open the database file *file* and return a corresponding object. If the database file already exists, the :func:`whichdb` function is used to determine its type and the appropriate module is used; if it does not exist, diff --git a/Doc/library/json.rst b/Doc/library/json.rst --- a/Doc/library/json.rst +++ b/Doc/library/json.rst @@ -34,7 +34,7 @@ Compact encoding:: >>> import json - >>> json.dumps([1,2,3,{'4': 5, '6': 7}], separators=(',',':')) + >>> json.dumps([1,2,3,{'4': 5, '6': 7}], separators=(',', ':')) '[1,2,3,{"4":5,"6":7}]' Pretty printing:: diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -447,8 +447,8 @@ This is called ``hexversion`` since it only really looks meaningful when viewed as the result of passing it to the built-in :func:`hex` function. The - ``version_info`` value may be used for a more human-friendly encoding of the - same information. + struct sequence :data:`sys.version_info` may be used for a more human-friendly + encoding of the same information. The ``hexversion`` is a 32-bit number with the following layout diff --git a/Doc/library/wsgiref.rst b/Doc/library/wsgiref.rst --- a/Doc/library/wsgiref.rst +++ b/Doc/library/wsgiref.rst @@ -664,7 +664,7 @@ .. attribute:: BaseHandler.wsgi_file_wrapper A ``wsgi.file_wrapper`` factory, or ``None``. The default value of this - attribute is the :class:`FileWrapper` class from :mod:`wsgiref.util`. + attribute is the :class:`wsgiref.util.FileWrapper` class. .. method:: BaseHandler.sendfile() diff --git a/Lib/dbm/__init__.py b/Lib/dbm/__init__.py --- a/Lib/dbm/__init__.py +++ b/Lib/dbm/__init__.py @@ -24,16 +24,8 @@ list = d.keys() # return a list of all existing keys (slow!) Future versions may change the order in which implementations are -tested for existence, add interfaces to other dbm-like +tested for existence, and add interfaces to other dbm-like implementations. - -The open function has an optional second argument. This can be 'r', -for read-only access, 'w', for read-write access of an existing -database, 'c' for read-write access to a new or existing database, and -'n' for read-write access to a new database. The default is 'r'. - -Note: 'r' and 'w' fail if the database doesn't exist; 'c' creates it -only if it doesn't exist; and 'n' always creates a new database. """ __all__ = ['open', 'whichdb', 'error', 'error'] @@ -54,7 +46,17 @@ error = (error, IOError) -def open(file, flag = 'r', mode = 0o666): +def open(file, flag='r', mode=0o666): + """Open or create database at path given by *file*. + + Optional argument *flag* can be 'r' (default) for read-only access, 'w' + for read-write access of an existing database, 'c' for read-write access + to a new or existing database, and 'n' for read-write access to a new + database. + + Note: 'r' and 'w' fail if the database doesn't exist; 'c' creates it + only if it doesn't exist; and 'n' always creates a new database. + """ global _defaultmod if _defaultmod is None: for name in _names: diff --git a/Lib/distutils/command/sdist.py b/Lib/distutils/command/sdist.py --- a/Lib/distutils/command/sdist.py +++ b/Lib/distutils/command/sdist.py @@ -294,17 +294,20 @@ join_lines=1, lstrip_ws=1, rstrip_ws=1, collapse_join=1) - while True: - line = template.readline() - if line is None: # end of file - break + try: + while True: + line = template.readline() + if line is None: # end of file + break - try: - self.filelist.process_template_line(line) - except DistutilsTemplateError as msg: - self.warn("%s, line %d: %s" % (template.filename, - template.current_line, - msg)) + try: + self.filelist.process_template_line(line) + except DistutilsTemplateError as msg: + self.warn("%s, line %d: %s" % (template.filename, + template.current_line, + msg)) + finally: + template.close() def prune_file_list(self): """Prune off branches that might slip into the file list as created diff --git a/Lib/distutils/tests/test_register.py b/Lib/distutils/tests/test_register.py --- a/Lib/distutils/tests/test_register.py +++ b/Lib/distutils/tests/test_register.py @@ -137,7 +137,7 @@ # let's see what the server received : we should # have 2 similar requests - self.assertTrue(self.conn.reqs, 2) + self.assertEqual(len(self.conn.reqs), 2) req1 = dict(self.conn.reqs[0].headers) req2 = dict(self.conn.reqs[1].headers) @@ -169,7 +169,7 @@ del register_module.input # we should have send a request - self.assertTrue(self.conn.reqs, 1) + self.assertEqual(len(self.conn.reqs), 1) req = self.conn.reqs[0] headers = dict(req.headers) self.assertEqual(headers['Content-length'], '608') @@ -187,7 +187,7 @@ del register_module.input # we should have send a request - self.assertTrue(self.conn.reqs, 1) + self.assertEqual(len(self.conn.reqs), 1) req = self.conn.reqs[0] headers = dict(req.headers) self.assertEqual(headers['Content-length'], '290') diff --git a/Lib/heapq.py b/Lib/heapq.py --- a/Lib/heapq.py +++ b/Lib/heapq.py @@ -172,7 +172,7 @@ return item def heapify(x): - """Transform list into a heap, in-place, in O(len(heap)) time.""" + """Transform list into a heap, in-place, in O(len(x)) time.""" n = len(x) # Transform bottom-up. The largest index there's any point to looking at # is the largest with a child index in-range, so must have 2*i + 1 < n, @@ -363,7 +363,7 @@ return [min(chain(head, it))] return [min(chain(head, it), key=key)] - # When n>=size, it's faster to use sort() + # When n>=size, it's faster to use sorted() try: size = len(iterable) except (TypeError, AttributeError): @@ -401,7 +401,7 @@ return [max(chain(head, it))] return [max(chain(head, it), key=key)] - # When n>=size, it's faster to use sort() + # When n>=size, it's faster to use sorted() try: size = len(iterable) except (TypeError, AttributeError): diff --git a/Lib/json/__init__.py b/Lib/json/__init__.py --- a/Lib/json/__init__.py +++ b/Lib/json/__init__.py @@ -31,7 +31,7 @@ Compact encoding:: >>> import json - >>> json.dumps([1,2,3,{'4': 5, '6': 7}], separators=(',',':')) + >>> json.dumps([1,2,3,{'4': 5, '6': 7}], separators=(',', ':')) '[1,2,3,{"4":5,"6":7}]' Pretty printing:: diff --git a/Lib/test/tracedmodules/__init__.py b/Lib/test/tracedmodules/__init__.py --- a/Lib/test/tracedmodules/__init__.py +++ b/Lib/test/tracedmodules/__init__.py @@ -2,8 +2,3 @@ that the exact location of functions in these modules is important, as trace.py takes the real line numbers into account. """ -"""This directory contains modules that help testing the trace.py module. Note -that the exact location of functions in these modules is important, as trace.py -takes the real line numbers into account. - -""" -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 27 16:39:19 2011 From: python-checkins at python.org (eric.araujo) Date: Wed, 27 Apr 2011 16:39:19 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> 3.2): Branch merge Message-ID: http://hg.python.org/cpython/rev/c981a9824122 changeset: 69628:c981a9824122 branch: 3.2 parent: 69590:b316019638df parent: 69621:316a8f4d6617 user: ?ric Araujo date: Wed Apr 27 16:25:27 2011 +0200 summary: Branch merge files: Doc/c-api/intro.rst | 3 +- Doc/c-api/object.rst | 1 - Doc/distutils/examples.rst | 2 +- Doc/documenting/markup.rst | 25 +++++++++++++-- Doc/library/collections.rst | 4 +- Doc/library/dbm.rst | 4 +- Doc/library/json.rst | 2 +- Doc/library/runpy.rst | 2 +- Lib/ast.py | 4 +- Lib/dbm/__init__.py | 22 +++++++------ Lib/distutils/command/sdist.py | 23 ++++++++------ Lib/distutils/tests/test_register.py | 6 +- Lib/heapq.py | 6 +- Lib/json/__init__.py | 2 +- Lib/sysconfig.py | 1 - Lib/trace.py | 2 +- 16 files changed, 64 insertions(+), 45 deletions(-) diff --git a/Doc/c-api/intro.rst b/Doc/c-api/intro.rst --- a/Doc/c-api/intro.rst +++ b/Doc/c-api/intro.rst @@ -511,13 +511,12 @@ module: builtins module: __main__ module: sys - module: exceptions triple: module; search; path single: path (in module sys) The basic initialization function is :c:func:`Py_Initialize`. This initializes the table of loaded modules, and creates the fundamental modules -:mod:`builtins`, :mod:`__main__`, :mod:`sys`, and :mod:`exceptions`. It also +:mod:`builtins`, :mod:`__main__`, and :mod:`sys`. It also initializes the module search path (``sys.path``). .. index:: single: PySys_SetArgvEx() diff --git a/Doc/c-api/object.rst b/Doc/c-api/object.rst --- a/Doc/c-api/object.rst +++ b/Doc/c-api/object.rst @@ -258,7 +258,6 @@ This is the equivalent of the Python expression ``hash(o)``. .. versionchanged:: 3.2 - The return type is now Py_hash_t. This is a signed integer the same size as Py_ssize_t. diff --git a/Doc/distutils/examples.rst b/Doc/distutils/examples.rst --- a/Doc/distutils/examples.rst +++ b/Doc/distutils/examples.rst @@ -279,7 +279,7 @@ Where the long description is broken, ``check`` will be able to detect it by using the :mod:`docutils` parser:: - $ pythontrunk setup.py check --restructuredtext + $ python setup.py check --restructuredtext running check warning: check: Title underline too short. (line 2) warning: check: Could not finish the parsing. diff --git a/Doc/documenting/markup.rst b/Doc/documenting/markup.rst --- a/Doc/documenting/markup.rst +++ b/Doc/documenting/markup.rst @@ -152,7 +152,7 @@ Describes global data in a module, including both variables and values used as "defined constants." Class and object attributes are not documented - using this environment. + using this directive. .. describe:: exception @@ -165,7 +165,7 @@ parameters, enclosing optional parameters in brackets. Default values can be given if it enhances clarity. For example:: - .. function:: Timer.repeat([repeat=3[, number=1000000]]) + .. function:: repeat([repeat=3[, number=1000000]]) Object methods are not documented using this directive. Bound object methods placed in the module namespace as part of the public interface of the module @@ -217,13 +217,30 @@ Describes an object data attribute. The description should include information about the type of the data to be expected and whether it may be - changed directly. + changed directly. This directive should be nested in a class directive, + like in this example:: + + .. class:: Spam + + Description of the class. + + .. data:: ham + + Description of the attribute. + + If is also possible to document an attribute outside of a class directive, + for example if the documentation for different attributes and methods is + split in multiple sections. The class name should then be included + explicitly:: + + .. data:: Spam.eggs .. describe:: method Describes an object method. The parameters should not include the ``self`` parameter. The description should include similar information to that - described for ``function``. + described for ``function``. This method should be nested in a class + method, like in the example above. .. describe:: decoratormethod diff --git a/Doc/library/collections.rst b/Doc/library/collections.rst --- a/Doc/library/collections.rst +++ b/Doc/library/collections.rst @@ -205,14 +205,14 @@ * `Bag class `_ in Smalltalk. - * Wikipedia entry for `Multisets `_\. + * Wikipedia entry for `Multisets `_. * `C++ multisets `_ tutorial with examples. * For mathematical operations on multisets and their use cases, see *Knuth, Donald. The Art of Computer Programming Volume II, - Section 4.6.3, Exercise 19*\. + Section 4.6.3, Exercise 19*. * To enumerate all distinct multisets of a given size over a given set of elements, see :func:`itertools.combinations_with_replacement`. diff --git a/Doc/library/dbm.rst b/Doc/library/dbm.rst --- a/Doc/library/dbm.rst +++ b/Doc/library/dbm.rst @@ -30,9 +30,9 @@ name, such as ``'dbm.ndbm'`` or ``'dbm.gnu'``. -.. function:: open(filename, flag='r', mode=0o666) +.. function:: open(file, flag='r', mode=0o666) - Open the database file *filename* and return a corresponding object. + Open the database file *file* and return a corresponding object. If the database file already exists, the :func:`whichdb` function is used to determine its type and the appropriate module is used; if it does not exist, diff --git a/Doc/library/json.rst b/Doc/library/json.rst --- a/Doc/library/json.rst +++ b/Doc/library/json.rst @@ -34,7 +34,7 @@ Compact encoding:: >>> import json - >>> json.dumps([1,2,3,{'4': 5, '6': 7}], separators=(',',':')) + >>> json.dumps([1,2,3,{'4': 5, '6': 7}], separators=(',', ':')) '[1,2,3,{"4":5,"6":7}]' Pretty printing:: diff --git a/Doc/library/runpy.rst b/Doc/library/runpy.rst --- a/Doc/library/runpy.rst +++ b/Doc/library/runpy.rst @@ -49,7 +49,7 @@ loader does not make filename information available, this variable is set to :const:`None`. - ``__cached__`` will be set to ``None``. + ``__cached__`` will be set to ``None``. ``__loader__`` is set to the :pep:`302` module loader used to retrieve the code for the module (This loader may be a wrapper around the standard diff --git a/Lib/ast.py b/Lib/ast.py --- a/Lib/ast.py +++ b/Lib/ast.py @@ -40,8 +40,8 @@ """ Safely evaluate an expression node or a string containing a Python expression. The string or node provided may only consist of the following - Python literal structures: strings, numbers, tuples, lists, dicts, booleans, - and None. + Python literal structures: strings, bytes, numbers, tuples, lists, dicts, + sets, booleans, and None. """ _safe_names = {'None': None, 'True': True, 'False': False} if isinstance(node_or_string, str): diff --git a/Lib/dbm/__init__.py b/Lib/dbm/__init__.py --- a/Lib/dbm/__init__.py +++ b/Lib/dbm/__init__.py @@ -23,16 +23,8 @@ list = d.keys() # return a list of all existing keys (slow!) Future versions may change the order in which implementations are -tested for existence, add interfaces to other dbm-like +tested for existence, and add interfaces to other dbm-like implementations. - -The open function has an optional second argument. This can be 'r', -for read-only access, 'w', for read-write access of an existing -database, 'c' for read-write access to a new or existing database, and -'n' for read-write access to a new database. The default is 'r'. - -Note: 'r' and 'w' fail if the database doesn't exist; 'c' creates it -only if it doesn't exist; and 'n' always creates a new database. """ __all__ = ['open', 'whichdb', 'error'] @@ -53,7 +45,17 @@ error = (error, IOError) -def open(file, flag = 'r', mode = 0o666): +def open(file, flag='r', mode=0o666): + """Open or create database at path given by *file*. + + Optional argument *flag* can be 'r' (default) for read-only access, 'w' + for read-write access of an existing database, 'c' for read-write access + to a new or existing database, and 'n' for read-write access to a new + database. + + Note: 'r' and 'w' fail if the database doesn't exist; 'c' creates it + only if it doesn't exist; and 'n' always creates a new database. + """ global _defaultmod if _defaultmod is None: for name in _names: diff --git a/Lib/distutils/command/sdist.py b/Lib/distutils/command/sdist.py --- a/Lib/distutils/command/sdist.py +++ b/Lib/distutils/command/sdist.py @@ -294,17 +294,20 @@ join_lines=1, lstrip_ws=1, rstrip_ws=1, collapse_join=1) - while True: - line = template.readline() - if line is None: # end of file - break + try: + while True: + line = template.readline() + if line is None: # end of file + break - try: - self.filelist.process_template_line(line) - except DistutilsTemplateError as msg: - self.warn("%s, line %d: %s" % (template.filename, - template.current_line, - msg)) + try: + self.filelist.process_template_line(line) + except DistutilsTemplateError as msg: + self.warn("%s, line %d: %s" % (template.filename, + template.current_line, + msg)) + finally: + template.close() def prune_file_list(self): """Prune off branches that might slip into the file list as created diff --git a/Lib/distutils/tests/test_register.py b/Lib/distutils/tests/test_register.py --- a/Lib/distutils/tests/test_register.py +++ b/Lib/distutils/tests/test_register.py @@ -137,7 +137,7 @@ # let's see what the server received : we should # have 2 similar requests - self.assertTrue(self.conn.reqs, 2) + self.assertEqual(len(self.conn.reqs), 2) req1 = dict(self.conn.reqs[0].headers) req2 = dict(self.conn.reqs[1].headers) @@ -169,7 +169,7 @@ del register_module.input # we should have send a request - self.assertTrue(self.conn.reqs, 1) + self.assertEqual(len(self.conn.reqs), 1) req = self.conn.reqs[0] headers = dict(req.headers) self.assertEqual(headers['Content-length'], '608') @@ -187,7 +187,7 @@ del register_module.input # we should have send a request - self.assertTrue(self.conn.reqs, 1) + self.assertEqual(len(self.conn.reqs), 1) req = self.conn.reqs[0] headers = dict(req.headers) self.assertEqual(headers['Content-length'], '290') diff --git a/Lib/heapq.py b/Lib/heapq.py --- a/Lib/heapq.py +++ b/Lib/heapq.py @@ -170,7 +170,7 @@ return item def heapify(x): - """Transform list into a heap, in-place, in O(len(heap)) time.""" + """Transform list into a heap, in-place, in O(len(x)) time.""" n = len(x) # Transform bottom-up. The largest index there's any point to looking at # is the largest with a child index in-range, so must have 2*i + 1 < n, @@ -360,7 +360,7 @@ return [min(chain(head, it))] return [min(chain(head, it), key=key)] - # When n>=size, it's faster to use sort() + # When n>=size, it's faster to use sorted() try: size = len(iterable) except (TypeError, AttributeError): @@ -398,7 +398,7 @@ return [max(chain(head, it))] return [max(chain(head, it), key=key)] - # When n>=size, it's faster to use sort() + # When n>=size, it's faster to use sorted() try: size = len(iterable) except (TypeError, AttributeError): diff --git a/Lib/json/__init__.py b/Lib/json/__init__.py --- a/Lib/json/__init__.py +++ b/Lib/json/__init__.py @@ -31,7 +31,7 @@ Compact encoding:: >>> import json - >>> json.dumps([1,2,3,{'4': 5, '6': 7}], separators=(',',':')) + >>> json.dumps([1,2,3,{'4': 5, '6': 7}], separators=(',', ':')) '[1,2,3,{"4":5,"6":7}]' Pretty printing:: diff --git a/Lib/sysconfig.py b/Lib/sysconfig.py --- a/Lib/sysconfig.py +++ b/Lib/sysconfig.py @@ -694,7 +694,6 @@ m = re.search( r'ProductUserVisibleVersion\s*' + r'(.*?)', f.read()) - f.close() if m is not None: macrelease = '.'.join(m.group(1).split('.')[:2]) # else: fall back to the default behaviour diff --git a/Lib/trace.py b/Lib/trace.py --- a/Lib/trace.py +++ b/Lib/trace.py @@ -688,7 +688,7 @@ for opt, val in opts: if opt == "--help": - usage(sys.stdout) + _usage(sys.stdout) sys.exit(0) if opt == "--version": -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 27 16:39:21 2011 From: python-checkins at python.org (eric.araujo) Date: Wed, 27 Apr 2011 16:39:21 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): Merge 3.1 Message-ID: http://hg.python.org/cpython/rev/0ff8f6105827 changeset: 69629:0ff8f6105827 branch: 3.2 parent: 69628:c981a9824122 parent: 69627:aca7a3091c9b user: ?ric Araujo date: Wed Apr 27 16:27:38 2011 +0200 summary: Merge 3.1 files: Doc/library/__future__.rst | 2 +- Doc/library/sys.rst | 4 ++-- Doc/library/wsgiref.rst | 2 +- Lib/test/tracedmodules/__init__.py | 5 ----- 4 files changed, 4 insertions(+), 9 deletions(-) diff --git a/Doc/library/__future__.rst b/Doc/library/__future__.rst --- a/Doc/library/__future__.rst +++ b/Doc/library/__future__.rst @@ -29,7 +29,7 @@ where, normally, *OptionalRelease* is less than *MandatoryRelease*, and both are -5-tuples of the same form as ``sys.version_info``:: +5-tuples of the same form as :data:`sys.version_info`:: (PY_MAJOR_VERSION, # the 2 in 2.1.0a3; an int PY_MINOR_VERSION, # the 1; an int diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -549,8 +549,8 @@ This is called ``hexversion`` since it only really looks meaningful when viewed as the result of passing it to the built-in :func:`hex` function. The - ``version_info`` value may be used for a more human-friendly encoding of the - same information. + struct sequence :data:`sys.version_info` may be used for a more human-friendly + encoding of the same information. The ``hexversion`` is a 32-bit number with the following layout diff --git a/Doc/library/wsgiref.rst b/Doc/library/wsgiref.rst --- a/Doc/library/wsgiref.rst +++ b/Doc/library/wsgiref.rst @@ -690,7 +690,7 @@ .. attribute:: BaseHandler.wsgi_file_wrapper A ``wsgi.file_wrapper`` factory, or ``None``. The default value of this - attribute is the :class:`FileWrapper` class from :mod:`wsgiref.util`. + attribute is the :class:`wsgiref.util.FileWrapper` class. .. method:: BaseHandler.sendfile() diff --git a/Lib/test/tracedmodules/__init__.py b/Lib/test/tracedmodules/__init__.py --- a/Lib/test/tracedmodules/__init__.py +++ b/Lib/test/tracedmodules/__init__.py @@ -2,8 +2,3 @@ that the exact location of functions in these modules is important, as trace.py takes the real line numbers into account. """ -"""This directory contains modules that help testing the trace.py module. Note -that the exact location of functions in these modules is important, as trace.py -takes the real line numbers into account. - -""" -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 27 16:39:24 2011 From: python-checkins at python.org (eric.araujo) Date: Wed, 27 Apr 2011 16:39:24 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge 3.2 Message-ID: http://hg.python.org/cpython/rev/cd6dfe6dd3a3 changeset: 69630:cd6dfe6dd3a3 parent: 69623:95f9c2d6a1e7 parent: 69629:0ff8f6105827 user: ?ric Araujo date: Wed Apr 27 16:32:36 2011 +0200 summary: Merge 3.2 files: Doc/c-api/object.rst | 1 - Doc/library/__future__.rst | 2 +- Doc/library/sys.rst | 4 ++-- Doc/library/wsgiref.rst | 2 +- Lib/test/tracedmodules/__init__.py | 5 ----- 5 files changed, 4 insertions(+), 10 deletions(-) diff --git a/Doc/c-api/object.rst b/Doc/c-api/object.rst --- a/Doc/c-api/object.rst +++ b/Doc/c-api/object.rst @@ -258,7 +258,6 @@ This is the equivalent of the Python expression ``hash(o)``. .. versionchanged:: 3.2 - The return type is now Py_hash_t. This is a signed integer the same size as Py_ssize_t. diff --git a/Doc/library/__future__.rst b/Doc/library/__future__.rst --- a/Doc/library/__future__.rst +++ b/Doc/library/__future__.rst @@ -29,7 +29,7 @@ where, normally, *OptionalRelease* is less than *MandatoryRelease*, and both are -5-tuples of the same form as ``sys.version_info``:: +5-tuples of the same form as :data:`sys.version_info`:: (PY_MAJOR_VERSION, # the 2 in 2.1.0a3; an int PY_MINOR_VERSION, # the 1; an int diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -540,8 +540,8 @@ This is called ``hexversion`` since it only really looks meaningful when viewed as the result of passing it to the built-in :func:`hex` function. The - ``version_info`` value may be used for a more human-friendly encoding of the - same information. + :term:`struct sequence` :data:`sys.version_info` may be used for a more + human-friendly encoding of the same information. The ``hexversion`` is a 32-bit number with the following layout diff --git a/Doc/library/wsgiref.rst b/Doc/library/wsgiref.rst --- a/Doc/library/wsgiref.rst +++ b/Doc/library/wsgiref.rst @@ -690,7 +690,7 @@ .. attribute:: BaseHandler.wsgi_file_wrapper A ``wsgi.file_wrapper`` factory, or ``None``. The default value of this - attribute is the :class:`FileWrapper` class from :mod:`wsgiref.util`. + attribute is the :class:`wsgiref.util.FileWrapper` class. .. method:: BaseHandler.sendfile() diff --git a/Lib/test/tracedmodules/__init__.py b/Lib/test/tracedmodules/__init__.py --- a/Lib/test/tracedmodules/__init__.py +++ b/Lib/test/tracedmodules/__init__.py @@ -2,8 +2,3 @@ that the exact location of functions in these modules is important, as trace.py takes the real line numbers into account. """ -"""This directory contains modules that help testing the trace.py module. Note -that the exact location of functions in these modules is important, as trace.py -takes the real line numbers into account. - -""" -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 27 18:14:35 2011 From: python-checkins at python.org (lukasz.langa) Date: Wed, 27 Apr 2011 18:14:35 +0200 Subject: [Python-checkins] cpython (3.2): Closes #11670: configparser read_file now iterates over f. Message-ID: http://hg.python.org/cpython/rev/6f937d6369b6 changeset: 69631:6f937d6369b6 branch: 3.2 parent: 69629:0ff8f6105827 user: ?ukasz Langa date: Wed Apr 27 18:10:05 2011 +0200 summary: Closes #11670: configparser read_file now iterates over f. files: Doc/library/configparser.rst | 29 ++++++++++-- Lib/configparser.py | 8 +- Lib/test/test_cfgparser.py | 54 ++++++++++++++++++++++++ 3 files changed, 82 insertions(+), 9 deletions(-) diff --git a/Doc/library/configparser.rst b/Doc/library/configparser.rst --- a/Doc/library/configparser.rst +++ b/Doc/library/configparser.rst @@ -974,18 +974,37 @@ .. method:: read_file(f, source=None) - Read and parse configuration data from the file or file-like object in - *f* (only the :meth:`readline` method is used). The file-like object - must operate in text mode. Specifically, it must return strings from - :meth:`readline`. + Read and parse configuration data from *f* which must be an iterable + yielding Unicode strings (for example any file object). Optional argument *source* specifies the name of the file being read. If not given and *f* has a :attr:`name` attribute, that is used for *source*; the default is ``''``. .. versionadded:: 3.2 - Replaces :meth:`readfp`. + Replaces :meth:`readfp`. + + .. note:: + + Prior to Python 3.2, :meth:`readfp` consumed lines from the file-like + argument by calling its :meth:`~file.readline` method. For existing code + calling :meth:`readfp` with arguments which don't support iteration, + the following generator may be used as a wrapper around the file-like + object:: + def readline_generator(f): + line = f.readline() + while line != '': + yield line + line = f.readline() + + Before:: + + parser.readfp(f) + + After:: + + parser.read_file(readline_generator(f)) .. method:: read_string(string, source='') diff --git a/Lib/configparser.py b/Lib/configparser.py --- a/Lib/configparser.py +++ b/Lib/configparser.py @@ -694,10 +694,10 @@ def read_file(self, f, source=None): """Like read() but the argument must be a file-like object. - The `f' argument must have a `readline' method. Optional second - argument is the `source' specifying the name of the file being read. If - not given, it is taken from f.name. If `f' has no `name' attribute, - `' is used. + The `f' argument must be iterable, returning one line at a time. + Optional second argument is the `source' specifying the name of the + file being read. If not given, it is taken from f.name. If `f' has no + `name' attribute, `' is used. """ if source is None: try: diff --git a/Lib/test/test_cfgparser.py b/Lib/test/test_cfgparser.py --- a/Lib/test/test_cfgparser.py +++ b/Lib/test/test_cfgparser.py @@ -1235,6 +1235,59 @@ del section[default] return cf_copy + +class FakeFile: + def __init__(self): + file_path = support.findfile("cfgparser.1") + with open(file_path) as f: + self.lines = f.readlines() + self.lines.reverse() + + def readline(self): + if len(self.lines): + return self.lines.pop() + return '' + + +def readline_generator(f): + """As advised in Doc/library/configparser.rst.""" + line = f.readline() + while line != '': + yield line + line = f.readline() + + +class ReadFileTestCase(unittest.TestCase): + def test_file(self): + file_path = support.findfile("cfgparser.1") + parser = configparser.ConfigParser() + with open(file_path) as f: + parser.read_file(f) + self.assertTrue("Foo Bar" in parser) + self.assertTrue("foo" in parser["Foo Bar"]) + self.assertEqual(parser["Foo Bar"]["foo"], "newbar") + + def test_iterable(self): + lines = textwrap.dedent(""" + [Foo Bar] + foo=newbar""").strip().split('\n') + parser = configparser.ConfigParser() + parser.read_file(lines) + self.assertTrue("Foo Bar" in parser) + self.assertTrue("foo" in parser["Foo Bar"]) + self.assertEqual(parser["Foo Bar"]["foo"], "newbar") + + def test_readline_generator(self): + """Issue #11670.""" + parser = configparser.ConfigParser() + with self.assertRaises(TypeError): + parser.read_file(FakeFile()) + parser.read_file(readline_generator(FakeFile())) + self.assertTrue("Foo Bar" in parser) + self.assertTrue("foo" in parser["Foo Bar"]) + self.assertEqual(parser["Foo Bar"]["foo"], "newbar") + + class CoverageOneHundredTestCase(unittest.TestCase): """Covers edge cases in the codebase.""" @@ -1338,5 +1391,6 @@ CompatibleTestCase, CopyTestCase, ConfigParserTestCaseNonStandardDefaultSection, + ReadFileTestCase, CoverageOneHundredTestCase, ) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 27 18:14:36 2011 From: python-checkins at python.org (lukasz.langa) Date: Wed, 27 Apr 2011 18:14:36 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merged #11670 from 3.2 Message-ID: http://hg.python.org/cpython/rev/9da06f771a57 changeset: 69632:9da06f771a57 parent: 69630:cd6dfe6dd3a3 parent: 69631:6f937d6369b6 user: ?ukasz Langa date: Wed Apr 27 18:11:50 2011 +0200 summary: Merged #11670 from 3.2 files: Doc/library/configparser.rst | 29 ++++++++++-- Lib/configparser.py | 8 +- Lib/test/test_configparser.py | 54 +++++++++++++++++++++++ 3 files changed, 82 insertions(+), 9 deletions(-) diff --git a/Doc/library/configparser.rst b/Doc/library/configparser.rst --- a/Doc/library/configparser.rst +++ b/Doc/library/configparser.rst @@ -974,18 +974,37 @@ .. method:: read_file(f, source=None) - Read and parse configuration data from the file or file-like object in - *f* (only the :meth:`readline` method is used). The file-like object - must operate in text mode. Specifically, it must return strings from - :meth:`readline`. + Read and parse configuration data from *f* which must be an iterable + yielding Unicode strings (for example any file object). Optional argument *source* specifies the name of the file being read. If not given and *f* has a :attr:`name` attribute, that is used for *source*; the default is ``''``. .. versionadded:: 3.2 - Replaces :meth:`readfp`. + Replaces :meth:`readfp`. + + .. note:: + + Prior to Python 3.2, :meth:`readfp` consumed lines from the file-like + argument by calling its :meth:`~file.readline` method. For existing code + calling :meth:`readfp` with arguments which don't support iteration, + the following generator may be used as a wrapper around the file-like + object:: + def readline_generator(f): + line = f.readline() + while line != '': + yield line + line = f.readline() + + Before:: + + parser.readfp(f) + + After:: + + parser.read_file(readline_generator(f)) .. method:: read_string(string, source='') diff --git a/Lib/configparser.py b/Lib/configparser.py --- a/Lib/configparser.py +++ b/Lib/configparser.py @@ -695,10 +695,10 @@ def read_file(self, f, source=None): """Like read() but the argument must be a file-like object. - The `f' argument must have a `readline' method. Optional second - argument is the `source' specifying the name of the file being read. If - not given, it is taken from f.name. If `f' has no `name' attribute, - `' is used. + The `f' argument must be iterable, returning one line at a time. + Optional second argument is the `source' specifying the name of the + file being read. If not given, it is taken from f.name. If `f' has no + `name' attribute, `' is used. """ if source is None: try: diff --git a/Lib/test/test_configparser.py b/Lib/test/test_configparser.py --- a/Lib/test/test_configparser.py +++ b/Lib/test/test_configparser.py @@ -1235,6 +1235,59 @@ del section[default] return cf_copy + +class FakeFile: + def __init__(self): + file_path = support.findfile("cfgparser.1") + with open(file_path) as f: + self.lines = f.readlines() + self.lines.reverse() + + def readline(self): + if len(self.lines): + return self.lines.pop() + return '' + + +def readline_generator(f): + """As advised in Doc/library/configparser.rst.""" + line = f.readline() + while line != '': + yield line + line = f.readline() + + +class ReadFileTestCase(unittest.TestCase): + def test_file(self): + file_path = support.findfile("cfgparser.1") + parser = configparser.ConfigParser() + with open(file_path) as f: + parser.read_file(f) + self.assertTrue("Foo Bar" in parser) + self.assertTrue("foo" in parser["Foo Bar"]) + self.assertEqual(parser["Foo Bar"]["foo"], "newbar") + + def test_iterable(self): + lines = textwrap.dedent(""" + [Foo Bar] + foo=newbar""").strip().split('\n') + parser = configparser.ConfigParser() + parser.read_file(lines) + self.assertTrue("Foo Bar" in parser) + self.assertTrue("foo" in parser["Foo Bar"]) + self.assertEqual(parser["Foo Bar"]["foo"], "newbar") + + def test_readline_generator(self): + """Issue #11670.""" + parser = configparser.ConfigParser() + with self.assertRaises(TypeError): + parser.read_file(FakeFile()) + parser.read_file(readline_generator(FakeFile())) + self.assertTrue("Foo Bar" in parser) + self.assertTrue("foo" in parser["Foo Bar"]) + self.assertEqual(parser["Foo Bar"]["foo"], "newbar") + + class CoverageOneHundredTestCase(unittest.TestCase): """Covers edge cases in the codebase.""" @@ -1338,5 +1391,6 @@ CompatibleTestCase, CopyTestCase, ConfigParserTestCaseNonStandardDefaultSection, + ReadFileTestCase, CoverageOneHundredTestCase, ) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 27 18:14:37 2011 From: python-checkins at python.org (lukasz.langa) Date: Wed, 27 Apr 2011 18:14:37 +0200 Subject: [Python-checkins] cpython (3.2): Fixed trailing whitespace in the ReST file. Message-ID: http://hg.python.org/cpython/rev/ace8e8a0e3dc changeset: 69633:ace8e8a0e3dc branch: 3.2 parent: 69631:6f937d6369b6 user: ?ukasz Langa date: Wed Apr 27 18:13:42 2011 +0200 summary: Fixed trailing whitespace in the ReST file. files: Doc/library/configparser.rst | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/library/configparser.rst b/Doc/library/configparser.rst --- a/Doc/library/configparser.rst +++ b/Doc/library/configparser.rst @@ -982,10 +982,10 @@ *source*; the default is ``''``. .. versionadded:: 3.2 - Replaces :meth:`readfp`. - + Replaces :meth:`readfp`. + .. note:: - + Prior to Python 3.2, :meth:`readfp` consumed lines from the file-like argument by calling its :meth:`~file.readline` method. For existing code calling :meth:`readfp` with arguments which don't support iteration, -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 27 18:14:39 2011 From: python-checkins at python.org (lukasz.langa) Date: Wed, 27 Apr 2011 18:14:39 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merged trailing whitespace fix. Message-ID: http://hg.python.org/cpython/rev/6ba0c3ee34af changeset: 69634:6ba0c3ee34af parent: 69632:9da06f771a57 parent: 69633:ace8e8a0e3dc user: ?ukasz Langa date: Wed Apr 27 18:14:04 2011 +0200 summary: Merged trailing whitespace fix. files: Doc/library/configparser.rst | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/library/configparser.rst b/Doc/library/configparser.rst --- a/Doc/library/configparser.rst +++ b/Doc/library/configparser.rst @@ -982,10 +982,10 @@ *source*; the default is ``''``. .. versionadded:: 3.2 - Replaces :meth:`readfp`. - + Replaces :meth:`readfp`. + .. note:: - + Prior to Python 3.2, :meth:`readfp` consumed lines from the file-like argument by calling its :meth:`~file.readline` method. For existing code calling :meth:`readfp` with arguments which don't support iteration, -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 27 19:22:15 2011 From: python-checkins at python.org (antoine.pitrou) Date: Wed, 27 Apr 2011 19:22:15 +0200 Subject: [Python-checkins] cpython (2.7): Issue #10517: After fork(), reinitialize the TLS used by the PyGILState_* Message-ID: http://hg.python.org/cpython/rev/f6feed6ec3f9 changeset: 69635:f6feed6ec3f9 branch: 2.7 parent: 69588:8dbf661c0a63 user: Antoine Pitrou date: Wed Apr 27 19:20:48 2011 +0200 summary: Issue #10517: After fork(), reinitialize the TLS used by the PyGILState_* APIs, to avoid a crash with the pthread implementation in RHEL 5. Patch by Charles-Fran?ois Natali. files: Include/pystate.h | 1 + Misc/NEWS | 4 ++++ Modules/signalmodule.c | 1 + Python/pystate.c | 17 +++++++++++++++++ 4 files changed, 23 insertions(+), 0 deletions(-) diff --git a/Include/pystate.h b/Include/pystate.h --- a/Include/pystate.h +++ b/Include/pystate.h @@ -111,6 +111,7 @@ PyAPI_FUNC(void) PyThreadState_Delete(PyThreadState *); #ifdef WITH_THREAD PyAPI_FUNC(void) PyThreadState_DeleteCurrent(void); +PyAPI_FUNC(void) _PyGILState_Reinit(void); #endif PyAPI_FUNC(PyThreadState *) PyThreadState_Get(void); diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -61,6 +61,10 @@ Library ------- +- Issue #10517: After fork(), reinitialize the TLS used by the PyGILState_* + APIs, to avoid a crash with the pthread implementation in RHEL 5. Patch + by Charles-Fran?ois Natali. + - Issue #11763: don't use difflib in TestCase.assertMultiLineEqual if the strings are too long. diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c --- a/Modules/signalmodule.c +++ b/Modules/signalmodule.c @@ -976,6 +976,7 @@ PyOS_AfterFork(void) { #ifdef WITH_THREAD + _PyGILState_Reinit(); PyEval_ReInitThreads(); main_thread = PyThread_get_thread_ident(); main_pid = getpid(); diff --git a/Python/pystate.c b/Python/pystate.c --- a/Python/pystate.c +++ b/Python/pystate.c @@ -537,6 +537,23 @@ autoInterpreterState = NULL; } +/* Reset the TLS key - called by PyOS_AfterFork. + * This should not be necessary, but some - buggy - pthread implementations + * don't flush TLS on fork, see issue #10517. + */ +void +_PyGILState_Reinit(void) +{ + PyThreadState *tstate = PyGILState_GetThisThreadState(); + PyThread_delete_key(autoTLSkey); + if ((autoTLSkey = PyThread_create_key()) == -1) + Py_FatalError("Could not allocate TLS entry"); + + /* re-associate the current thread state with the new key */ + if (PyThread_set_key_value(autoTLSkey, (void *)tstate) < 0) + Py_FatalError("Couldn't create autoTLSkey mapping"); +} + /* When a thread state is created for a thread by some mechanism other than PyGILState_Ensure, it's important that the GILState machinery knows about it so it doesn't try to create another thread state for the thread (this is -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 27 19:26:20 2011 From: python-checkins at python.org (antoine.pitrou) Date: Wed, 27 Apr 2011 19:26:20 +0200 Subject: [Python-checkins] cpython (2.7): Move NEWS entry to the right section. Message-ID: http://hg.python.org/cpython/rev/60d4a00ec3b3 changeset: 69636:60d4a00ec3b3 branch: 2.7 user: Antoine Pitrou date: Wed Apr 27 19:26:06 2011 +0200 summary: Move NEWS entry to the right section. files: Misc/NEWS | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -9,6 +9,10 @@ Core and Builtins ----------------- +- Issue #10517: After fork(), reinitialize the TLS used by the PyGILState_* + APIs, to avoid a crash with the pthread implementation in RHEL 5. Patch + by Charles-Fran?ois Natali. + - Issue #6780: fix starts/endswith error message to mention that tuples are accepted too. @@ -61,10 +65,6 @@ Library ------- -- Issue #10517: After fork(), reinitialize the TLS used by the PyGILState_* - APIs, to avoid a crash with the pthread implementation in RHEL 5. Patch - by Charles-Fran?ois Natali. - - Issue #11763: don't use difflib in TestCase.assertMultiLineEqual if the strings are too long. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 27 19:38:18 2011 From: python-checkins at python.org (antoine.pitrou) Date: Wed, 27 Apr 2011 19:38:18 +0200 Subject: [Python-checkins] cpython (3.2): Issue #10517: After fork(), reinitialize the TLS used by the PyGILState_* Message-ID: http://hg.python.org/cpython/rev/7b7ad9a88451 changeset: 69637:7b7ad9a88451 branch: 3.2 parent: 69633:ace8e8a0e3dc user: Antoine Pitrou date: Wed Apr 27 19:28:05 2011 +0200 summary: Issue #10517: After fork(), reinitialize the TLS used by the PyGILState_* APIs, to avoid a crash with the pthread implementation in RHEL 5. Patch by Charles-Fran?ois Natali. files: Include/pystate.h | 1 + Misc/NEWS | 4 ++++ Modules/signalmodule.c | 1 + Python/pystate.c | 17 +++++++++++++++++ 4 files changed, 23 insertions(+), 0 deletions(-) diff --git a/Include/pystate.h b/Include/pystate.h --- a/Include/pystate.h +++ b/Include/pystate.h @@ -131,6 +131,7 @@ PyAPI_FUNC(void) PyThreadState_Delete(PyThreadState *); #ifdef WITH_THREAD PyAPI_FUNC(void) PyThreadState_DeleteCurrent(void); +PyAPI_FUNC(void) _PyGILState_Reinit(void); #endif PyAPI_FUNC(PyThreadState *) PyThreadState_Get(void); diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,10 @@ Core and Builtins ----------------- +- Issue #10517: After fork(), reinitialize the TLS used by the PyGILState_* + APIs, to avoid a crash with the pthread implementation in RHEL 5. Patch + by Charles-Fran?ois Natali. + - Issue #6780: fix starts/endswith error message to mention that tuples are accepted too. diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c --- a/Modules/signalmodule.c +++ b/Modules/signalmodule.c @@ -991,6 +991,7 @@ PyOS_AfterFork(void) { #ifdef WITH_THREAD + _PyGILState_Reinit(); PyEval_ReInitThreads(); main_thread = PyThread_get_thread_ident(); main_pid = getpid(); diff --git a/Python/pystate.c b/Python/pystate.c --- a/Python/pystate.c +++ b/Python/pystate.c @@ -585,6 +585,23 @@ autoInterpreterState = NULL; } +/* Reset the TLS key - called by PyOS_AfterFork. + * This should not be necessary, but some - buggy - pthread implementations + * don't flush TLS on fork, see issue #10517. + */ +void +_PyGILState_Reinit(void) +{ + PyThreadState *tstate = PyGILState_GetThisThreadState(); + PyThread_delete_key(autoTLSkey); + if ((autoTLSkey = PyThread_create_key()) == -1) + Py_FatalError("Could not allocate TLS entry"); + + /* re-associate the current thread state with the new key */ + if (PyThread_set_key_value(autoTLSkey, (void *)tstate) < 0) + Py_FatalError("Couldn't create autoTLSkey mapping"); +} + /* When a thread state is created for a thread by some mechanism other than PyGILState_Ensure, it's important that the GILState machinery knows about it so it doesn't try to create another thread state for the thread (this is -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 27 19:38:19 2011 From: python-checkins at python.org (antoine.pitrou) Date: Wed, 27 Apr 2011 19:38:19 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Issue #10517: After fork(), reinitialize the TLS used by the PyGILState_* Message-ID: http://hg.python.org/cpython/rev/c8f283cd3e6e changeset: 69638:c8f283cd3e6e parent: 69634:6ba0c3ee34af parent: 69637:7b7ad9a88451 user: Antoine Pitrou date: Wed Apr 27 19:30:16 2011 +0200 summary: Issue #10517: After fork(), reinitialize the TLS used by the PyGILState_* APIs, to avoid a crash with the pthread implementation in RHEL 5. Patch by Charles-Fran?ois Natali. files: Include/pystate.h | 1 + Misc/NEWS | 4 ++++ Modules/signalmodule.c | 1 + Python/pystate.c | 17 +++++++++++++++++ 4 files changed, 23 insertions(+), 0 deletions(-) diff --git a/Include/pystate.h b/Include/pystate.h --- a/Include/pystate.h +++ b/Include/pystate.h @@ -132,6 +132,7 @@ PyAPI_FUNC(void) PyThreadState_Delete(PyThreadState *); #ifdef WITH_THREAD PyAPI_FUNC(void) PyThreadState_DeleteCurrent(void); +PyAPI_FUNC(void) _PyGILState_Reinit(void); #endif PyAPI_FUNC(PyThreadState *) PyThreadState_Get(void); diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,10 @@ Core and Builtins ----------------- +- Issue #10517: After fork(), reinitialize the TLS used by the PyGILState_* + APIs, to avoid a crash with the pthread implementation in RHEL 5. Patch + by Charles-Fran?ois Natali. + - Issue #10914: Initialize correctly the filesystem codec when creating a new subinterpreter to fix a bootstrap issue with codecs implemented in Python, as the ISO-8859-15 codec. diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c --- a/Modules/signalmodule.c +++ b/Modules/signalmodule.c @@ -991,6 +991,7 @@ PyOS_AfterFork(void) { #ifdef WITH_THREAD + _PyGILState_Reinit(); PyEval_ReInitThreads(); main_thread = PyThread_get_thread_ident(); main_pid = getpid(); diff --git a/Python/pystate.c b/Python/pystate.c --- a/Python/pystate.c +++ b/Python/pystate.c @@ -586,6 +586,23 @@ autoInterpreterState = NULL; } +/* Reset the TLS key - called by PyOS_AfterFork. + * This should not be necessary, but some - buggy - pthread implementations + * don't flush TLS on fork, see issue #10517. + */ +void +_PyGILState_Reinit(void) +{ + PyThreadState *tstate = PyGILState_GetThisThreadState(); + PyThread_delete_key(autoTLSkey); + if ((autoTLSkey = PyThread_create_key()) == -1) + Py_FatalError("Could not allocate TLS entry"); + + /* re-associate the current thread state with the new key */ + if (PyThread_set_key_value(autoTLSkey, (void *)tstate) < 0) + Py_FatalError("Couldn't create autoTLSkey mapping"); +} + /* When a thread state is created for a thread by some mechanism other than PyGILState_Ensure, it's important that the GILState machinery knows about it so it doesn't try to create another thread state for the thread (this is -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 27 23:53:58 2011 From: python-checkins at python.org (ezio.melotti) Date: Wed, 27 Apr 2011 23:53:58 +0200 Subject: [Python-checkins] cpython (2.7): #11942: Fix return type of Py_AddPendingCall. Patch by Sandro Tosi. Message-ID: http://hg.python.org/cpython/rev/6739b9ab7ced changeset: 69639:6739b9ab7ced branch: 2.7 parent: 69636:60d4a00ec3b3 user: Ezio Melotti date: Thu Apr 28 00:48:46 2011 +0300 summary: #11942: Fix return type of Py_AddPendingCall. Patch by Sandro Tosi. files: Doc/c-api/init.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -906,7 +906,7 @@ main thread where it has possession of the global interpreter lock and can perform any Python API calls. -.. cfunction:: void Py_AddPendingCall(int (*func)(void *), void *arg) +.. cfunction:: int Py_AddPendingCall(int (*func)(void *), void *arg) .. index:: single: Py_AddPendingCall() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 27 23:53:59 2011 From: python-checkins at python.org (ezio.melotti) Date: Wed, 27 Apr 2011 23:53:59 +0200 Subject: [Python-checkins] cpython (3.1): #11942: Fix return type of Py_AddPendingCall. Patch by Sandro Tosi. Message-ID: http://hg.python.org/cpython/rev/fd1f47a57ba2 changeset: 69640:fd1f47a57ba2 branch: 3.1 parent: 69627:aca7a3091c9b user: Ezio Melotti date: Thu Apr 28 00:48:46 2011 +0300 summary: #11942: Fix return type of Py_AddPendingCall. Patch by Sandro Tosi. files: Doc/c-api/init.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -892,7 +892,7 @@ main thread where it has possession of the global interpreter lock and can perform any Python API calls. -.. cfunction:: void Py_AddPendingCall(int (*func)(void *), void *arg) +.. cfunction:: int Py_AddPendingCall(int (*func)(void *), void *arg) .. index:: single: Py_AddPendingCall() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 27 23:54:01 2011 From: python-checkins at python.org (ezio.melotti) Date: Wed, 27 Apr 2011 23:54:01 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): #11942: merge with 3.1. Message-ID: http://hg.python.org/cpython/rev/119c7219b1ac changeset: 69641:119c7219b1ac branch: 3.2 parent: 69637:7b7ad9a88451 parent: 69640:fd1f47a57ba2 user: Ezio Melotti date: Thu Apr 28 00:53:14 2011 +0300 summary: #11942: merge with 3.1. files: Doc/c-api/init.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -908,7 +908,7 @@ main thread where it has possession of the global interpreter lock and can perform any Python API calls. -.. c:function:: void Py_AddPendingCall(int (*func)(void *), void *arg) +.. c:function:: int Py_AddPendingCall(int (*func)(void *), void *arg) .. index:: single: Py_AddPendingCall() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Apr 27 23:54:03 2011 From: python-checkins at python.org (ezio.melotti) Date: Wed, 27 Apr 2011 23:54:03 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): #11942: merge with 3.2. Message-ID: http://hg.python.org/cpython/rev/1cdcd1a25025 changeset: 69642:1cdcd1a25025 parent: 69638:c8f283cd3e6e parent: 69641:119c7219b1ac user: Ezio Melotti date: Thu Apr 28 00:53:48 2011 +0300 summary: #11942: merge with 3.2. files: Doc/c-api/init.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -908,7 +908,7 @@ main thread where it has possession of the global interpreter lock and can perform any Python API calls. -.. c:function:: void Py_AddPendingCall(int (*func)(void *), void *arg) +.. c:function:: int Py_AddPendingCall(int (*func)(void *), void *arg) .. index:: single: Py_AddPendingCall() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Apr 28 00:00:35 2011 From: python-checkins at python.org (ezio.melotti) Date: Thu, 28 Apr 2011 00:00:35 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): #11938: merge with 3.2. Message-ID: http://hg.python.org/cpython/rev/bdd6d8631994 changeset: 69644:bdd6d8631994 parent: 69642:1cdcd1a25025 parent: 69643:ef35dae58077 user: Ezio Melotti date: Thu Apr 28 01:00:25 2011 +0300 summary: #11938: merge with 3.2. files: Lib/test/test_inspect.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -801,7 +801,7 @@ thing = Thing() self.assertEqual(inspect.getattr_static(thing, 'x'), Thing.x) - def test_descriptor(self): + def test_descriptor_raises_AttributeError(self): class descriptor(object): def __get__(*_): raise AttributeError("I'm pretending not to exist") -- Repository URL: http://hg.python.org/cpython From ezio.melotti at gmail.com Thu Apr 28 00:46:06 2011 From: ezio.melotti at gmail.com (Ezio Melotti) Date: Thu, 28 Apr 2011 01:46:06 +0300 Subject: [Python-checkins] cpython (3.2): Closes #11670: configparser read_file now iterates over f. In-Reply-To: References: Message-ID: <4DB89CAE.3070407@gmail.com> Hi, On 27/04/2011 19.14, lukasz.langa wrote: > http://hg.python.org/cpython/rev/6f937d6369b6 > changeset: 69631:6f937d6369b6 > branch: 3.2 > parent: 69629:0ff8f6105827 > user: ?ukasz Langa > date: Wed Apr 27 18:10:05 2011 +0200 > summary: > Closes #11670: configparser read_file now iterates over f. > > files: > Doc/library/configparser.rst | 29 ++++++++++-- > Lib/configparser.py | 8 +- > Lib/test/test_cfgparser.py | 54 ++++++++++++++++++++++++ > 3 files changed, 82 insertions(+), 9 deletions(-) > > > diff --git a/Doc/library/configparser.rst b/Doc/library/configparser.rst > --- a/Doc/library/configparser.rst > +++ b/Doc/library/configparser.rst > @@ -974,18 +974,37 @@ > > .. method:: read_file(f, source=None) > > - Read and parse configuration data from the file or file-like object in > - *f* (only the :meth:`readline` method is used). The file-like object > - must operate in text mode. Specifically, it must return strings from > - :meth:`readline`. > + Read and parse configuration data from *f* which must be an iterable > + yielding Unicode strings (for example any file object). I wouldn't use 'any' here. File objects opened in binary mode will yield byte strings. > > Optional argument *source* specifies the name of the file being read. If > not given and *f* has a :attr:`name` attribute, that is used for > *source*; the default is ``''``. > > .. versionadded:: 3.2 > - Replaces :meth:`readfp`. > + Replaces :meth:`readfp`. > + > + .. note:: > + > + Prior to Python 3.2, This note could be a versionchanged and be less verbose (e.g. the before/after could be replaced by something like "and use it as parser.read_file(readline_generator(f))"). > :meth:`readfp` consumed lines from the file-like > + argument by calling its :meth:`~file.readline` method. For existing code > + calling :meth:`readfp` with arguments which don't support iteration, > + the following generator may be used as a wrapper around the file-like > + object:: > > + def readline_generator(f): > + line = f.readline() > + while line != '': The "!= ''" can probably go. > + yield line > + line = f.readline() > + > + Before:: > + > + parser.readfp(f) > + > + After:: > + > + parser.read_file(readline_generator(f)) > > .. method:: read_string(string, source='') > > diff --git a/Lib/configparser.py b/Lib/configparser.py > --- a/Lib/configparser.py > +++ b/Lib/configparser.py > @@ -694,10 +694,10 @@ > def read_file(self, f, source=None): > """Like read() but the argument must be a file-like object. > > - The `f' argument must have a `readline' method. Optional second > - argument is the `source' specifying the name of the file being read. If > - not given, it is taken from f.name. If `f' has no `name' attribute, > - `' is used. > + The `f' argument must be iterable, returning one line at a time. > + Optional second argument is the `source' specifying the name of the > + file being read. If not given, it is taken from f.name. If `f' has no > + `name' attribute, `' is used. > """ > if source is None: > try: > diff --git a/Lib/test/test_cfgparser.py b/Lib/test/test_cfgparser.py > --- a/Lib/test/test_cfgparser.py > +++ b/Lib/test/test_cfgparser.py > @@ -1235,6 +1235,59 @@ > del section[default] > return cf_copy > > + > +class FakeFile: > + def __init__(self): > + file_path = support.findfile("cfgparser.1") > + with open(file_path) as f: > + self.lines = f.readlines() > + self.lines.reverse() > + > + def readline(self): > + if len(self.lines): > + return self.lines.pop() > + return '' > + > + > +def readline_generator(f): > + """As advised in Doc/library/configparser.rst.""" > + line = f.readline() > + while line != '': Ditto. > + yield line > + line = f.readline() > + > + > +class ReadFileTestCase(unittest.TestCase): > + def test_file(self): > + file_path = support.findfile("cfgparser.1") > + parser = configparser.ConfigParser() > + with open(file_path) as f: > + parser.read_file(f) > + self.assertTrue("Foo Bar" in parser) > + self.assertTrue("foo" in parser["Foo Bar"]) These should be 'assertIn'. > + self.assertEqual(parser["Foo Bar"]["foo"], "newbar") > + > + def test_iterable(self): > + lines = textwrap.dedent(""" > + [Foo Bar] > + foo=newbar""").strip().split('\n') > + parser = configparser.ConfigParser() > + parser.read_file(lines) > + self.assertTrue("Foo Bar" in parser) > + self.assertTrue("foo" in parser["Foo Bar"]) Ditto. > + self.assertEqual(parser["Foo Bar"]["foo"], "newbar") > + > + def test_readline_generator(self): > + """Issue #11670.""" > + parser = configparser.ConfigParser() > + with self.assertRaises(TypeError): > + parser.read_file(FakeFile()) > + parser.read_file(readline_generator(FakeFile())) > + self.assertTrue("Foo Bar" in parser) > + self.assertTrue("foo" in parser["Foo Bar"]) Ditto. > + self.assertEqual(parser["Foo Bar"]["foo"], "newbar") > + > + > class CoverageOneHundredTestCase(unittest.TestCase): > """Covers edge cases in the codebase.""" > > @@ -1338,5 +1391,6 @@ > CompatibleTestCase, > CopyTestCase, > ConfigParserTestCaseNonStandardDefaultSection, > + ReadFileTestCase, > CoverageOneHundredTestCase, > ) Best Regards, Ezio Melotti From python-checkins at python.org Thu Apr 28 01:33:14 2011 From: python-checkins at python.org (raymond.hettinger) Date: Thu, 28 Apr 2011 01:33:14 +0200 Subject: [Python-checkins] cpython (3.1): Issue #11940: Update external link. Message-ID: http://hg.python.org/cpython/rev/4c5babbf7a73 changeset: 69645:4c5babbf7a73 branch: 3.1 parent: 69640:fd1f47a57ba2 user: Raymond Hettinger date: Wed Apr 27 16:32:08 2011 -0700 summary: Issue #11940: Update external link. files: Doc/howto/advocacy.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/howto/advocacy.rst b/Doc/howto/advocacy.rst --- a/Doc/howto/advocacy.rst +++ b/Doc/howto/advocacy.rst @@ -308,7 +308,7 @@ buying, but the publishers have made the first chapter available on the Web. -http://home.pacbell.net/ouster/scripting.html +http://www.tcl.tk/doc/scripting.html John Ousterhout's white paper on scripting is a good argument for the utility of scripting languages, though naturally enough, he emphasizes Tcl, the language he developed. Most of the arguments would apply to any scripting language. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Apr 28 01:33:15 2011 From: python-checkins at python.org (raymond.hettinger) Date: Thu, 28 Apr 2011 01:33:15 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): Issue #11940: Update external link. Message-ID: http://hg.python.org/cpython/rev/08647ab0ead7 changeset: 69646:08647ab0ead7 branch: 3.2 parent: 69643:ef35dae58077 parent: 69645:4c5babbf7a73 user: Raymond Hettinger date: Wed Apr 27 16:32:34 2011 -0700 summary: Issue #11940: Update external link. files: Doc/howto/advocacy.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/howto/advocacy.rst b/Doc/howto/advocacy.rst --- a/Doc/howto/advocacy.rst +++ b/Doc/howto/advocacy.rst @@ -308,7 +308,7 @@ buying, but the publishers have made the first chapter available on the Web. -http://home.pacbell.net/ouster/scripting.html +http://www.tcl.tk/doc/scripting.html John Ousterhout's white paper on scripting is a good argument for the utility of scripting languages, though naturally enough, he emphasizes Tcl, the language he developed. Most of the arguments would apply to any scripting language. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Apr 28 01:33:16 2011 From: python-checkins at python.org (raymond.hettinger) Date: Thu, 28 Apr 2011 01:33:16 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Issue #11940: Update external link. Message-ID: http://hg.python.org/cpython/rev/618642ba7551 changeset: 69647:618642ba7551 parent: 69644:bdd6d8631994 parent: 69646:08647ab0ead7 user: Raymond Hettinger date: Wed Apr 27 16:33:01 2011 -0700 summary: Issue #11940: Update external link. files: Doc/howto/advocacy.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/howto/advocacy.rst b/Doc/howto/advocacy.rst --- a/Doc/howto/advocacy.rst +++ b/Doc/howto/advocacy.rst @@ -308,7 +308,7 @@ buying, but the publishers have made the first chapter available on the Web. -http://home.pacbell.net/ouster/scripting.html +http://www.tcl.tk/doc/scripting.html John Ousterhout's white paper on scripting is a good argument for the utility of scripting languages, though naturally enough, he emphasizes Tcl, the language he developed. Most of the arguments would apply to any scripting language. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Apr 28 01:34:16 2011 From: python-checkins at python.org (raymond.hettinger) Date: Thu, 28 Apr 2011 01:34:16 +0200 Subject: [Python-checkins] cpython (2.7): Issue #11940: Update external link. Message-ID: http://hg.python.org/cpython/rev/eb7c4526ccbf changeset: 69648:eb7c4526ccbf branch: 2.7 parent: 69639:6739b9ab7ced user: Raymond Hettinger date: Wed Apr 27 16:34:07 2011 -0700 summary: Issue #11940: Update external link. files: Doc/howto/advocacy.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/howto/advocacy.rst b/Doc/howto/advocacy.rst --- a/Doc/howto/advocacy.rst +++ b/Doc/howto/advocacy.rst @@ -308,7 +308,7 @@ buying, but the publishers have made the first chapter available on the Web. -http://home.pacbell.net/ouster/scripting.html +http://www.tcl.tk/doc/scripting.html John Ousterhout's white paper on scripting is a good argument for the utility of scripting languages, though naturally enough, he emphasizes Tcl, the language he developed. Most of the arguments would apply to any scripting language. -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Thu Apr 28 04:58:16 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Thu, 28 Apr 2011 04:58:16 +0200 Subject: [Python-checkins] Daily reference leaks (618642ba7551): sum=0 Message-ID: results for 618642ba7551 on branch "default" -------------------------------------------- test_pydoc leaked [0, -323, 323] references, sum=0 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogVc3Acc', '-x'] From python-checkins at python.org Thu Apr 28 06:59:48 2011 From: python-checkins at python.org (ezio.melotti) Date: Thu, 28 Apr 2011 06:59:48 +0200 Subject: [Python-checkins] cpython (3.1): #11926: add missing keywords to help("keywords"). Message-ID: http://hg.python.org/cpython/rev/99d5542399a1 changeset: 69649:99d5542399a1 branch: 3.1 parent: 69645:4c5babbf7a73 user: Ezio Melotti date: Thu Apr 28 07:42:55 2011 +0300 summary: #11926: add missing keywords to help("keywords"). files: Lib/pydoc.py | 11 +++- Lib/pydoc_data/topics.py | 70 ++++++++++++++-------------- Lib/test/test_pydoc.py | 8 ++- 3 files changed, 51 insertions(+), 38 deletions(-) diff --git a/Lib/pydoc.py b/Lib/pydoc.py --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -1538,6 +1538,9 @@ # in Doc/ and copying the output file into the Lib/ directory. keywords = { + 'False': '', + 'None': '', + 'True': '', 'and': 'BOOLEAN', 'as': 'with', 'assert': ('assert', ''), @@ -1552,12 +1555,13 @@ 'finally': 'try', 'for': ('for', 'break continue while'), 'from': 'import', - 'global': ('global', 'NAMESPACES'), + 'global': ('global', 'nonlocal NAMESPACES'), 'if': ('if', 'TRUTHVALUE'), 'import': ('import', 'MODULES'), 'in': ('in', 'SEQUENCEMETHODS'), 'is': 'COMPARISON', 'lambda': ('lambda', 'FUNCTIONS'), + 'nonlocal': ('nonlocal', 'global NAMESPACES'), 'not': 'BOOLEAN', 'or': 'BOOLEAN', 'pass': ('pass', ''), @@ -1652,7 +1656,7 @@ 'NUMBERMETHODS': ('numeric-types', 'NUMBERS AUGMENTEDASSIGNMENT ' 'SPECIALMETHODS'), 'EXECUTION': ('execmodel', 'NAMESPACES DYNAMICFEATURES EXCEPTIONS'), - 'NAMESPACES': ('naming', 'global ASSIGNMENT DELETION DYNAMICFEATURES'), + 'NAMESPACES': ('naming', 'global nonlocal ASSIGNMENT DELETION DYNAMICFEATURES'), 'DYNAMICFEATURES': ('dynamic-features', ''), 'SCOPING': 'NAMESPACES', 'FRAMES': 'NAMESPACES', @@ -1752,6 +1756,9 @@ elif request[:8] == 'modules ': self.listmodules(request.split()[1]) elif request in self.symbols: self.showsymbol(request) + elif request in ['True', 'False', 'None']: + # special case these keywords since they are objects too + doc(eval(request), 'Help on %s:') elif request in self.keywords: self.showtopic(request) elif request in self.topics: self.showtopic(request) elif request: doc(request, 'Help on %s:') diff --git a/Lib/pydoc_data/topics.py b/Lib/pydoc_data/topics.py --- a/Lib/pydoc_data/topics.py +++ b/Lib/pydoc_data/topics.py @@ -1,78 +1,78 @@ -# Autogenerated by Sphinx on Fri Jun 26 08:03:32 2009 +# Autogenerated by Sphinx on Thu Apr 28 07:37:19 2011 topics = {'assert': '\nThe ``assert`` statement\n************************\n\nAssert statements are a convenient way to insert debugging assertions\ninto a program:\n\n assert_stmt ::= "assert" expression ["," expression]\n\nThe simple form, ``assert expression``, is equivalent to\n\n if __debug__:\n if not expression: raise AssertionError\n\nThe extended form, ``assert expression1, expression2``, is equivalent\nto\n\n if __debug__:\n if not expression1: raise AssertionError(expression2)\n\nThese equivalences assume that ``__debug__`` and ``AssertionError``\nrefer to the built-in variables with those names. In the current\nimplementation, the built-in variable ``__debug__`` is ``True`` under\nnormal circumstances, ``False`` when optimization is requested\n(command line option -O). The current code generator emits no code\nfor an assert statement when optimization is requested at compile\ntime. Note that it is unnecessary to include the source code for the\nexpression that failed in the error message; it will be displayed as\npart of the stack trace.\n\nAssignments to ``__debug__`` are illegal. The value for the built-in\nvariable is determined when the interpreter starts.\n', - 'assignment': '\nAssignment statements\n*********************\n\nAssignment statements are used to (re)bind names to values and to\nmodify attributes or items of mutable objects:\n\n assignment_stmt ::= (target_list "=")+ (expression_list | yield_expression)\n target_list ::= target ("," target)* [","]\n target ::= identifier\n | "(" target_list ")"\n | "[" target_list "]"\n | attributeref\n | subscription\n | slicing\n | "*" target\n\n(See section *Primaries* for the syntax definitions for the last three\nsymbols.)\n\nAn assignment statement evaluates the expression list (remember that\nthis can be a single expression or a comma-separated list, the latter\nyielding a tuple) and assigns the single resulting object to each of\nthe target lists, from left to right.\n\nAssignment is defined recursively depending on the form of the target\n(list). When a target is part of a mutable object (an attribute\nreference, subscription or slicing), the mutable object must\nultimately perform the assignment and decide about its validity, and\nmay raise an exception if the assignment is unacceptable. The rules\nobserved by various types and the exceptions raised are given with the\ndefinition of the object types (see section *The standard type\nhierarchy*).\n\nAssignment of an object to a target list, optionally enclosed in\nparentheses or square brackets, is recursively defined as follows.\n\n* If the target list is a single target: The object is assigned to\n that target.\n\n* If the target list is a comma-separated list of targets: The object\n must be an iterable with the same number of items as there are\n targets in the target list, and the items are assigned, from left to\n right, to the corresponding targets. (This rule is relaxed as of\n Python 1.5; in earlier versions, the object had to be a tuple.\n Since strings are sequences, an assignment like ``a, b = "xy"`` is\n now legal as long as the string has the right length.)\n\n * If the target list contains one target prefixed with an asterisk,\n called a "starred" target: The object must be a sequence with at\n least as many items as there are targets in the target list, minus\n one. The first items of the sequence are assigned, from left to\n right, to the targets before the starred target. The final items\n of the sequence are assigned to the targets after the starred\n target. A list of the remaining items in the sequence is then\n assigned to the starred target (the list can be empty).\n\n * Else: The object must be a sequence with the same number of items\n as there are targets in the target list, and the items are\n assigned, from left to right, to the corresponding targets.\n\nAssignment of an object to a single target is recursively defined as\nfollows.\n\n* If the target is an identifier (name):\n\n * If the name does not occur in a ``global`` or ``nonlocal``\n statement in the current code block: the name is bound to the\n object in the current local namespace.\n\n * Otherwise: the name is bound to the object in the global namespace\n or the outer namespace determined by ``nonlocal``, respectively.\n\n The name is rebound if it was already bound. This may cause the\n reference count for the object previously bound to the name to reach\n zero, causing the object to be deallocated and its destructor (if it\n has one) to be called.\n\n The name is rebound if it was already bound. This may cause the\n reference count for the object previously bound to the name to reach\n zero, causing the object to be deallocated and its destructor (if it\n has one) to be called.\n\n* If the target is a target list enclosed in parentheses or in square\n brackets: The object must be an iterable with the same number of\n items as there are targets in the target list, and its items are\n assigned, from left to right, to the corresponding targets.\n\n* If the target is an attribute reference: The primary expression in\n the reference is evaluated. It should yield an object with\n assignable attributes; if this is not the case, ``TypeError`` is\n raised. That object is then asked to assign the assigned object to\n the given attribute; if it cannot perform the assignment, it raises\n an exception (usually but not necessarily ``AttributeError``).\n\n* If the target is a subscription: The primary expression in the\n reference is evaluated. It should yield either a mutable sequence\n object (such as a list) or a mapping object (such as a dictionary).\n Next, the subscript expression is evaluated.\n\n If the primary is a mutable sequence object (such as a list), the\n subscript must yield an integer. If it is negative, the sequence\'s\n length is added to it. The resulting value must be a nonnegative\n integer less than the sequence\'s length, and the sequence is asked\n to assign the assigned object to its item with that index. If the\n index is out of range, ``IndexError`` is raised (assignment to a\n subscripted sequence cannot add new items to a list).\n\n If the primary is a mapping object (such as a dictionary), the\n subscript must have a type compatible with the mapping\'s key type,\n and the mapping is then asked to create a key/datum pair which maps\n the subscript to the assigned object. This can either replace an\n existing key/value pair with the same key value, or insert a new\n key/value pair (if no key with the same value existed).\n\n For user-defined objects, the ``__setitem__()`` method is called\n with appropriate arguments.\n\n* If the target is a slicing: The primary expression in the reference\n is evaluated. It should yield a mutable sequence object (such as a\n list). The assigned object should be a sequence object of the same\n type. Next, the lower and upper bound expressions are evaluated,\n insofar they are present; defaults are zero and the sequence\'s\n length. The bounds should evaluate to integers. If either bound is\n negative, the sequence\'s length is added to it. The resulting\n bounds are clipped to lie between zero and the sequence\'s length,\n inclusive. Finally, the sequence object is asked to replace the\n slice with the items of the assigned sequence. The length of the\n slice may be different from the length of the assigned sequence,\n thus changing the length of the target sequence, if the object\n allows it.\n\n(In the current implementation, the syntax for targets is taken to be\nthe same as for expressions, and invalid syntax is rejected during the\ncode generation phase, causing less detailed error messages.)\n\nWARNING: Although the definition of assignment implies that overlaps\nbetween the left-hand side and the right-hand side are \'safe\' (for\nexample ``a, b = b, a`` swaps two variables), overlaps *within* the\ncollection of assigned-to variables are not safe! For instance, the\nfollowing program prints ``[0, 2]``:\n\n x = [0, 1]\n i = 0\n i, x[i] = 1, 2\n print(x)\n\nSee also:\n\n **PEP 3132** - Extended Iterable Unpacking\n The specification for the ``*target`` feature.\n\n\nAugmented assignment statements\n===============================\n\nAugmented assignment is the combination, in a single statement, of a\nbinary operation and an assignment statement:\n\n augmented_assignment_stmt ::= augtarget augop (expression_list | yield_expression)\n augtarget ::= identifier | attributeref | subscription | slicing\n augop ::= "+=" | "-=" | "*=" | "/=" | "//=" | "%=" | "**="\n | ">>=" | "<<=" | "&=" | "^=" | "|="\n\n(See section *Primaries* for the syntax definitions for the last three\nsymbols.)\n\nAn augmented assignment evaluates the target (which, unlike normal\nassignment statements, cannot be an unpacking) and the expression\nlist, performs the binary operation specific to the type of assignment\non the two operands, and assigns the result to the original target.\nThe target is only evaluated once.\n\nAn augmented assignment expression like ``x += 1`` can be rewritten as\n``x = x + 1`` to achieve a similar, but not exactly equal effect. In\nthe augmented version, ``x`` is only evaluated once. Also, when\npossible, the actual operation is performed *in-place*, meaning that\nrather than creating a new object and assigning that to the target,\nthe old object is modified instead.\n\nWith the exception of assigning to tuples and multiple targets in a\nsingle statement, the assignment done by augmented assignment\nstatements is handled the same way as normal assignments. Similarly,\nwith the exception of the possible *in-place* behavior, the binary\noperation performed by augmented assignment is the same as the normal\nbinary operations.\n\nFor targets which are attribute references, the initial value is\nretrieved with a ``getattr()`` and the result is assigned with a\n``setattr()``. Notice that the two methods do not necessarily refer\nto the same variable. When ``getattr()`` refers to a class variable,\n``setattr()`` still writes to an instance variable. For example:\n\n class A:\n x = 3 # class variable\n a = A()\n a.x += 1 # writes a.x as 4 leaving A.x as 3\n', + 'assignment': '\nAssignment statements\n*********************\n\nAssignment statements are used to (re)bind names to values and to\nmodify attributes or items of mutable objects:\n\n assignment_stmt ::= (target_list "=")+ (expression_list | yield_expression)\n target_list ::= target ("," target)* [","]\n target ::= identifier\n | "(" target_list ")"\n | "[" target_list "]"\n | attributeref\n | subscription\n | slicing\n | "*" target\n\n(See section *Primaries* for the syntax definitions for the last three\nsymbols.)\n\nAn assignment statement evaluates the expression list (remember that\nthis can be a single expression or a comma-separated list, the latter\nyielding a tuple) and assigns the single resulting object to each of\nthe target lists, from left to right.\n\nAssignment is defined recursively depending on the form of the target\n(list). When a target is part of a mutable object (an attribute\nreference, subscription or slicing), the mutable object must\nultimately perform the assignment and decide about its validity, and\nmay raise an exception if the assignment is unacceptable. The rules\nobserved by various types and the exceptions raised are given with the\ndefinition of the object types (see section *The standard type\nhierarchy*).\n\nAssignment of an object to a target list, optionally enclosed in\nparentheses or square brackets, is recursively defined as follows.\n\n* If the target list is a single target: The object is assigned to\n that target.\n\n* If the target list is a comma-separated list of targets: The object\n must be an iterable with the same number of items as there are\n targets in the target list, and the items are assigned, from left to\n right, to the corresponding targets.\n\n * If the target list contains one target prefixed with an asterisk,\n called a "starred" target: The object must be a sequence with at\n least as many items as there are targets in the target list, minus\n one. The first items of the sequence are assigned, from left to\n right, to the targets before the starred target. The final items\n of the sequence are assigned to the targets after the starred\n target. A list of the remaining items in the sequence is then\n assigned to the starred target (the list can be empty).\n\n * Else: The object must be a sequence with the same number of items\n as there are targets in the target list, and the items are\n assigned, from left to right, to the corresponding targets.\n\nAssignment of an object to a single target is recursively defined as\nfollows.\n\n* If the target is an identifier (name):\n\n * If the name does not occur in a ``global`` or ``nonlocal``\n statement in the current code block: the name is bound to the\n object in the current local namespace.\n\n * Otherwise: the name is bound to the object in the global namespace\n or the outer namespace determined by ``nonlocal``, respectively.\n\n The name is rebound if it was already bound. This may cause the\n reference count for the object previously bound to the name to reach\n zero, causing the object to be deallocated and its destructor (if it\n has one) to be called.\n\n* If the target is a target list enclosed in parentheses or in square\n brackets: The object must be an iterable with the same number of\n items as there are targets in the target list, and its items are\n assigned, from left to right, to the corresponding targets.\n\n* If the target is an attribute reference: The primary expression in\n the reference is evaluated. It should yield an object with\n assignable attributes; if this is not the case, ``TypeError`` is\n raised. That object is then asked to assign the assigned object to\n the given attribute; if it cannot perform the assignment, it raises\n an exception (usually but not necessarily ``AttributeError``).\n\n Note: If the object is a class instance and the attribute reference\n occurs on both sides of the assignment operator, the RHS expression,\n ``a.x`` can access either an instance attribute or (if no instance\n attribute exists) a class attribute. The LHS target ``a.x`` is\n always set as an instance attribute, creating it if necessary.\n Thus, the two occurrences of ``a.x`` do not necessarily refer to the\n same attribute: if the RHS expression refers to a class attribute,\n the LHS creates a new instance attribute as the target of the\n assignment:\n\n class Cls:\n x = 3 # class variable\n inst = Cls()\n inst.x = inst.x + 1 # writes inst.x as 4 leaving Cls.x as 3\n\n This description does not necessarily apply to descriptor\n attributes, such as properties created with ``property()``.\n\n* If the target is a subscription: The primary expression in the\n reference is evaluated. It should yield either a mutable sequence\n object (such as a list) or a mapping object (such as a dictionary).\n Next, the subscript expression is evaluated.\n\n If the primary is a mutable sequence object (such as a list), the\n subscript must yield an integer. If it is negative, the sequence\'s\n length is added to it. The resulting value must be a nonnegative\n integer less than the sequence\'s length, and the sequence is asked\n to assign the assigned object to its item with that index. If the\n index is out of range, ``IndexError`` is raised (assignment to a\n subscripted sequence cannot add new items to a list).\n\n If the primary is a mapping object (such as a dictionary), the\n subscript must have a type compatible with the mapping\'s key type,\n and the mapping is then asked to create a key/datum pair which maps\n the subscript to the assigned object. This can either replace an\n existing key/value pair with the same key value, or insert a new\n key/value pair (if no key with the same value existed).\n\n For user-defined objects, the ``__setitem__()`` method is called\n with appropriate arguments.\n\n* If the target is a slicing: The primary expression in the reference\n is evaluated. It should yield a mutable sequence object (such as a\n list). The assigned object should be a sequence object of the same\n type. Next, the lower and upper bound expressions are evaluated,\n insofar they are present; defaults are zero and the sequence\'s\n length. The bounds should evaluate to integers. If either bound is\n negative, the sequence\'s length is added to it. The resulting\n bounds are clipped to lie between zero and the sequence\'s length,\n inclusive. Finally, the sequence object is asked to replace the\n slice with the items of the assigned sequence. The length of the\n slice may be different from the length of the assigned sequence,\n thus changing the length of the target sequence, if the object\n allows it.\n\n**CPython implementation detail:** In the current implementation, the\nsyntax for targets is taken to be the same as for expressions, and\ninvalid syntax is rejected during the code generation phase, causing\nless detailed error messages.\n\nWARNING: Although the definition of assignment implies that overlaps\nbetween the left-hand side and the right-hand side are \'safe\' (for\nexample ``a, b = b, a`` swaps two variables), overlaps *within* the\ncollection of assigned-to variables are not safe! For instance, the\nfollowing program prints ``[0, 2]``:\n\n x = [0, 1]\n i = 0\n i, x[i] = 1, 2\n print(x)\n\nSee also:\n\n **PEP 3132** - Extended Iterable Unpacking\n The specification for the ``*target`` feature.\n\n\nAugmented assignment statements\n===============================\n\nAugmented assignment is the combination, in a single statement, of a\nbinary operation and an assignment statement:\n\n augmented_assignment_stmt ::= augtarget augop (expression_list | yield_expression)\n augtarget ::= identifier | attributeref | subscription | slicing\n augop ::= "+=" | "-=" | "*=" | "/=" | "//=" | "%=" | "**="\n | ">>=" | "<<=" | "&=" | "^=" | "|="\n\n(See section *Primaries* for the syntax definitions for the last three\nsymbols.)\n\nAn augmented assignment evaluates the target (which, unlike normal\nassignment statements, cannot be an unpacking) and the expression\nlist, performs the binary operation specific to the type of assignment\non the two operands, and assigns the result to the original target.\nThe target is only evaluated once.\n\nAn augmented assignment expression like ``x += 1`` can be rewritten as\n``x = x + 1`` to achieve a similar, but not exactly equal effect. In\nthe augmented version, ``x`` is only evaluated once. Also, when\npossible, the actual operation is performed *in-place*, meaning that\nrather than creating a new object and assigning that to the target,\nthe old object is modified instead.\n\nWith the exception of assigning to tuples and multiple targets in a\nsingle statement, the assignment done by augmented assignment\nstatements is handled the same way as normal assignments. Similarly,\nwith the exception of the possible *in-place* behavior, the binary\noperation performed by augmented assignment is the same as the normal\nbinary operations.\n\nFor targets which are attribute references, the same *caveat about\nclass and instance attributes* applies as for regular assignments.\n', 'atom-identifiers': '\nIdentifiers (Names)\n*******************\n\nAn identifier occurring as an atom is a name. See section\n*Identifiers and keywords* for lexical definition and section *Naming\nand binding* for documentation of naming and binding.\n\nWhen the name is bound to an object, evaluation of the atom yields\nthat object. When a name is not bound, an attempt to evaluate it\nraises a ``NameError`` exception.\n\n**Private name mangling:** When an identifier that textually occurs in\na class definition begins with two or more underscore characters and\ndoes not end in two or more underscores, it is considered a *private\nname* of that class. Private names are transformed to a longer form\nbefore code is generated for them. The transformation inserts the\nclass name in front of the name, with leading underscores removed, and\na single underscore inserted in front of the class name. For example,\nthe identifier ``__spam`` occurring in a class named ``Ham`` will be\ntransformed to ``_Ham__spam``. This transformation is independent of\nthe syntactical context in which the identifier is used. If the\ntransformed name is extremely long (longer than 255 characters),\nimplementation defined truncation may happen. If the class name\nconsists only of underscores, no transformation is done.\n', 'atom-literals': "\nLiterals\n********\n\nPython supports string and bytes literals and various numeric\nliterals:\n\n literal ::= stringliteral | bytesliteral\n | integer | floatnumber | imagnumber\n\nEvaluation of a literal yields an object of the given type (string,\nbytes, integer, floating point number, complex number) with the given\nvalue. The value may be approximated in the case of floating point\nand imaginary (complex) literals. See section *Literals* for details.\n\nWith the exception of bytes literals, these all correspond to\nimmutable data types, and hence the object's identity is less\nimportant than its value. Multiple evaluations of literals with the\nsame value (either the same occurrence in the program text or a\ndifferent occurrence) may obtain the same object or a different object\nwith the same value.\n", - 'attribute-access': '\nCustomizing attribute access\n****************************\n\nThe following methods can be defined to customize the meaning of\nattribute access (use of, assignment to, or deletion of ``x.name``)\nfor class instances.\n\nobject.__getattr__(self, name)\n\n Called when an attribute lookup has not found the attribute in the\n usual places (i.e. it is not an instance attribute nor is it found\n in the class tree for ``self``). ``name`` is the attribute name.\n This method should return the (computed) attribute value or raise\n an ``AttributeError`` exception.\n\n Note that if the attribute is found through the normal mechanism,\n ``__getattr__()`` is not called. (This is an intentional asymmetry\n between ``__getattr__()`` and ``__setattr__()``.) This is done both\n for efficiency reasons and because otherwise ``__getattr__()``\n would have no way to access other attributes of the instance. Note\n that at least for instance variables, you can fake total control by\n not inserting any values in the instance attribute dictionary (but\n instead inserting them in another object). See the\n ``__getattribute__()`` method below for a way to actually get total\n control over attribute access.\n\nobject.__getattribute__(self, name)\n\n Called unconditionally to implement attribute accesses for\n instances of the class. If the class also defines\n ``__getattr__()``, the latter will not be called unless\n ``__getattribute__()`` either calls it explicitly or raises an\n ``AttributeError``. This method should return the (computed)\n attribute value or raise an ``AttributeError`` exception. In order\n to avoid infinite recursion in this method, its implementation\n should always call the base class method with the same name to\n access any attributes it needs, for example,\n ``object.__getattribute__(self, name)``.\n\n Note: This method may still be bypassed when looking up special methods\n as the result of implicit invocation via language syntax or\n builtin functions. See *Special method lookup*.\n\nobject.__setattr__(self, name, value)\n\n Called when an attribute assignment is attempted. This is called\n instead of the normal mechanism (i.e. store the value in the\n instance dictionary). *name* is the attribute name, *value* is the\n value to be assigned to it.\n\n If ``__setattr__()`` wants to assign to an instance attribute, it\n should call the base class method with the same name, for example,\n ``object.__setattr__(self, name, value)``.\n\nobject.__delattr__(self, name)\n\n Like ``__setattr__()`` but for attribute deletion instead of\n assignment. This should only be implemented if ``del obj.name`` is\n meaningful for the object.\n\nobject.__dir__(self)\n\n Called when ``dir()`` is called on the object. A list must be\n returned.\n\n\nImplementing Descriptors\n========================\n\nThe following methods only apply when an instance of the class\ncontaining the method (a so-called *descriptor* class) appears in the\nclass dictionary of another class, known as the *owner* class. In the\nexamples below, "the attribute" refers to the attribute whose name is\nthe key of the property in the owner class\' ``__dict__``.\n\nobject.__get__(self, instance, owner)\n\n Called to get the attribute of the owner class (class attribute\n access) or of an instance of that class (instance attribute\n access). *owner* is always the owner class, while *instance* is the\n instance that the attribute was accessed through, or ``None`` when\n the attribute is accessed through the *owner*. This method should\n return the (computed) attribute value or raise an\n ``AttributeError`` exception.\n\nobject.__set__(self, instance, value)\n\n Called to set the attribute on an instance *instance* of the owner\n class to a new value, *value*.\n\nobject.__delete__(self, instance)\n\n Called to delete the attribute on an instance *instance* of the\n owner class.\n\n\nInvoking Descriptors\n====================\n\nIn general, a descriptor is an object attribute with "binding\nbehavior", one whose attribute access has been overridden by methods\nin the descriptor protocol: ``__get__()``, ``__set__()``, and\n``__delete__()``. If any of those methods are defined for an object,\nit is said to be a descriptor.\n\nThe default behavior for attribute access is to get, set, or delete\nthe attribute from an object\'s dictionary. For instance, ``a.x`` has a\nlookup chain starting with ``a.__dict__[\'x\']``, then\n``type(a).__dict__[\'x\']``, and continuing through the base classes of\n``type(a)`` excluding metaclasses.\n\nHowever, if the looked-up value is an object defining one of the\ndescriptor methods, then Python may override the default behavior and\ninvoke the descriptor method instead. Where this occurs in the\nprecedence chain depends on which descriptor methods were defined and\nhow they were called.\n\nThe starting point for descriptor invocation is a binding, ``a.x``.\nHow the arguments are assembled depends on ``a``:\n\nDirect Call\n The simplest and least common call is when user code directly\n invokes a descriptor method: ``x.__get__(a)``.\n\nInstance Binding\n If binding to an object instance, ``a.x`` is transformed into the\n call: ``type(a).__dict__[\'x\'].__get__(a, type(a))``.\n\nClass Binding\n If binding to a class, ``A.x`` is transformed into the call:\n ``A.__dict__[\'x\'].__get__(None, A)``.\n\nSuper Binding\n If ``a`` is an instance of ``super``, then the binding ``super(B,\n obj).m()`` searches ``obj.__class__.__mro__`` for the base class\n ``A`` immediately preceding ``B`` and then invokes the descriptor\n with the call: ``A.__dict__[\'m\'].__get__(obj, A)``.\n\nFor instance bindings, the precedence of descriptor invocation depends\non the which descriptor methods are defined. Normally, data\ndescriptors define both ``__get__()`` and ``__set__()``, while non-\ndata descriptors have just the ``__get__()`` method. Data descriptors\nalways override a redefinition in an instance dictionary. In\ncontrast, non-data descriptors can be overridden by instances. [2]\n\nPython methods (including ``staticmethod()`` and ``classmethod()``)\nare implemented as non-data descriptors. Accordingly, instances can\nredefine and override methods. This allows individual instances to\nacquire behaviors that differ from other instances of the same class.\n\nThe ``property()`` function is implemented as a data descriptor.\nAccordingly, instances cannot override the behavior of a property.\n\n\n__slots__\n=========\n\nBy default, instances of classes have a dictionary for attribute\nstorage. This wastes space for objects having very few instance\nvariables. The space consumption can become acute when creating large\nnumbers of instances.\n\nThe default can be overridden by defining *__slots__* in a class\ndefinition. The *__slots__* declaration takes a sequence of instance\nvariables and reserves just enough space in each instance to hold a\nvalue for each variable. Space is saved because *__dict__* is not\ncreated for each instance.\n\nobject.__slots__\n\n This class variable can be assigned a string, iterable, or sequence\n of strings with variable names used by instances. If defined in a\n class, *__slots__* reserves space for the declared variables and\n prevents the automatic creation of *__dict__* and *__weakref__* for\n each instance.\n\n\nNotes on using *__slots__*\n--------------------------\n\n* When inheriting from a class without *__slots__*, the *__dict__*\n attribute of that class will always be accessible, so a *__slots__*\n definition in the subclass is meaningless.\n\n* Without a *__dict__* variable, instances cannot be assigned new\n variables not listed in the *__slots__* definition. Attempts to\n assign to an unlisted variable name raises ``AttributeError``. If\n dynamic assignment of new variables is desired, then add\n ``\'__dict__\'`` to the sequence of strings in the *__slots__*\n declaration.\n\n* Without a *__weakref__* variable for each instance, classes defining\n *__slots__* do not support weak references to its instances. If weak\n reference support is needed, then add ``\'__weakref__\'`` to the\n sequence of strings in the *__slots__* declaration.\n\n* *__slots__* are implemented at the class level by creating\n descriptors (*Implementing Descriptors*) for each variable name. As\n a result, class attributes cannot be used to set default values for\n instance variables defined by *__slots__*; otherwise, the class\n attribute would overwrite the descriptor assignment.\n\n* If a class defines a slot also defined in a base class, the instance\n variable defined by the base class slot is inaccessible (except by\n retrieving its descriptor directly from the base class). This\n renders the meaning of the program undefined. In the future, a\n check may be added to prevent this.\n\n* The action of a *__slots__* declaration is limited to the class\n where it is defined. As a result, subclasses will have a *__dict__*\n unless they also define *__slots__*.\n\n* Nonempty *__slots__* does not work for classes derived from\n "variable-length" built-in types such as ``int``, ``str`` and\n ``tuple``.\n\n* Any non-string iterable may be assigned to *__slots__*. Mappings may\n also be used; however, in the future, special meaning may be\n assigned to the values corresponding to each key.\n\n* *__class__* assignment works only if both classes have the same\n *__slots__*.\n', + 'attribute-access': '\nCustomizing attribute access\n****************************\n\nThe following methods can be defined to customize the meaning of\nattribute access (use of, assignment to, or deletion of ``x.name``)\nfor class instances.\n\nobject.__getattr__(self, name)\n\n Called when an attribute lookup has not found the attribute in the\n usual places (i.e. it is not an instance attribute nor is it found\n in the class tree for ``self``). ``name`` is the attribute name.\n This method should return the (computed) attribute value or raise\n an ``AttributeError`` exception.\n\n Note that if the attribute is found through the normal mechanism,\n ``__getattr__()`` is not called. (This is an intentional asymmetry\n between ``__getattr__()`` and ``__setattr__()``.) This is done both\n for efficiency reasons and because otherwise ``__getattr__()``\n would have no way to access other attributes of the instance. Note\n that at least for instance variables, you can fake total control by\n not inserting any values in the instance attribute dictionary (but\n instead inserting them in another object). See the\n ``__getattribute__()`` method below for a way to actually get total\n control over attribute access.\n\nobject.__getattribute__(self, name)\n\n Called unconditionally to implement attribute accesses for\n instances of the class. If the class also defines\n ``__getattr__()``, the latter will not be called unless\n ``__getattribute__()`` either calls it explicitly or raises an\n ``AttributeError``. This method should return the (computed)\n attribute value or raise an ``AttributeError`` exception. In order\n to avoid infinite recursion in this method, its implementation\n should always call the base class method with the same name to\n access any attributes it needs, for example,\n ``object.__getattribute__(self, name)``.\n\n Note: This method may still be bypassed when looking up special methods\n as the result of implicit invocation via language syntax or\n built-in functions. See *Special method lookup*.\n\nobject.__setattr__(self, name, value)\n\n Called when an attribute assignment is attempted. This is called\n instead of the normal mechanism (i.e. store the value in the\n instance dictionary). *name* is the attribute name, *value* is the\n value to be assigned to it.\n\n If ``__setattr__()`` wants to assign to an instance attribute, it\n should call the base class method with the same name, for example,\n ``object.__setattr__(self, name, value)``.\n\nobject.__delattr__(self, name)\n\n Like ``__setattr__()`` but for attribute deletion instead of\n assignment. This should only be implemented if ``del obj.name`` is\n meaningful for the object.\n\nobject.__dir__(self)\n\n Called when ``dir()`` is called on the object. A list must be\n returned.\n\n\nImplementing Descriptors\n========================\n\nThe following methods only apply when an instance of the class\ncontaining the method (a so-called *descriptor* class) appears in an\n*owner* class (the descriptor must be in either the owner\'s class\ndictionary or in the class dictionary for one of its parents). In the\nexamples below, "the attribute" refers to the attribute whose name is\nthe key of the property in the owner class\' ``__dict__``.\n\nobject.__get__(self, instance, owner)\n\n Called to get the attribute of the owner class (class attribute\n access) or of an instance of that class (instance attribute\n access). *owner* is always the owner class, while *instance* is the\n instance that the attribute was accessed through, or ``None`` when\n the attribute is accessed through the *owner*. This method should\n return the (computed) attribute value or raise an\n ``AttributeError`` exception.\n\nobject.__set__(self, instance, value)\n\n Called to set the attribute on an instance *instance* of the owner\n class to a new value, *value*.\n\nobject.__delete__(self, instance)\n\n Called to delete the attribute on an instance *instance* of the\n owner class.\n\n\nInvoking Descriptors\n====================\n\nIn general, a descriptor is an object attribute with "binding\nbehavior", one whose attribute access has been overridden by methods\nin the descriptor protocol: ``__get__()``, ``__set__()``, and\n``__delete__()``. If any of those methods are defined for an object,\nit is said to be a descriptor.\n\nThe default behavior for attribute access is to get, set, or delete\nthe attribute from an object\'s dictionary. For instance, ``a.x`` has a\nlookup chain starting with ``a.__dict__[\'x\']``, then\n``type(a).__dict__[\'x\']``, and continuing through the base classes of\n``type(a)`` excluding metaclasses.\n\nHowever, if the looked-up value is an object defining one of the\ndescriptor methods, then Python may override the default behavior and\ninvoke the descriptor method instead. Where this occurs in the\nprecedence chain depends on which descriptor methods were defined and\nhow they were called.\n\nThe starting point for descriptor invocation is a binding, ``a.x``.\nHow the arguments are assembled depends on ``a``:\n\nDirect Call\n The simplest and least common call is when user code directly\n invokes a descriptor method: ``x.__get__(a)``.\n\nInstance Binding\n If binding to an object instance, ``a.x`` is transformed into the\n call: ``type(a).__dict__[\'x\'].__get__(a, type(a))``.\n\nClass Binding\n If binding to a class, ``A.x`` is transformed into the call:\n ``A.__dict__[\'x\'].__get__(None, A)``.\n\nSuper Binding\n If ``a`` is an instance of ``super``, then the binding ``super(B,\n obj).m()`` searches ``obj.__class__.__mro__`` for the base class\n ``A`` immediately preceding ``B`` and then invokes the descriptor\n with the call: ``A.__dict__[\'m\'].__get__(obj, obj.__class__)``.\n\nFor instance bindings, the precedence of descriptor invocation depends\non the which descriptor methods are defined. A descriptor can define\nany combination of ``__get__()``, ``__set__()`` and ``__delete__()``.\nIf it does not define ``__get__()``, then accessing the attribute will\nreturn the descriptor object itself unless there is a value in the\nobject\'s instance dictionary. If the descriptor defines ``__set__()``\nand/or ``__delete__()``, it is a data descriptor; if it defines\nneither, it is a non-data descriptor. Normally, data descriptors\ndefine both ``__get__()`` and ``__set__()``, while non-data\ndescriptors have just the ``__get__()`` method. Data descriptors with\n``__set__()`` and ``__get__()`` defined always override a redefinition\nin an instance dictionary. In contrast, non-data descriptors can be\noverridden by instances.\n\nPython methods (including ``staticmethod()`` and ``classmethod()``)\nare implemented as non-data descriptors. Accordingly, instances can\nredefine and override methods. This allows individual instances to\nacquire behaviors that differ from other instances of the same class.\n\nThe ``property()`` function is implemented as a data descriptor.\nAccordingly, instances cannot override the behavior of a property.\n\n\n__slots__\n=========\n\nBy default, instances of classes have a dictionary for attribute\nstorage. This wastes space for objects having very few instance\nvariables. The space consumption can become acute when creating large\nnumbers of instances.\n\nThe default can be overridden by defining *__slots__* in a class\ndefinition. The *__slots__* declaration takes a sequence of instance\nvariables and reserves just enough space in each instance to hold a\nvalue for each variable. Space is saved because *__dict__* is not\ncreated for each instance.\n\nobject.__slots__\n\n This class variable can be assigned a string, iterable, or sequence\n of strings with variable names used by instances. If defined in a\n class, *__slots__* reserves space for the declared variables and\n prevents the automatic creation of *__dict__* and *__weakref__* for\n each instance.\n\n\nNotes on using *__slots__*\n--------------------------\n\n* When inheriting from a class without *__slots__*, the *__dict__*\n attribute of that class will always be accessible, so a *__slots__*\n definition in the subclass is meaningless.\n\n* Without a *__dict__* variable, instances cannot be assigned new\n variables not listed in the *__slots__* definition. Attempts to\n assign to an unlisted variable name raises ``AttributeError``. If\n dynamic assignment of new variables is desired, then add\n ``\'__dict__\'`` to the sequence of strings in the *__slots__*\n declaration.\n\n* Without a *__weakref__* variable for each instance, classes defining\n *__slots__* do not support weak references to its instances. If weak\n reference support is needed, then add ``\'__weakref__\'`` to the\n sequence of strings in the *__slots__* declaration.\n\n* *__slots__* are implemented at the class level by creating\n descriptors (*Implementing Descriptors*) for each variable name. As\n a result, class attributes cannot be used to set default values for\n instance variables defined by *__slots__*; otherwise, the class\n attribute would overwrite the descriptor assignment.\n\n* The action of a *__slots__* declaration is limited to the class\n where it is defined. As a result, subclasses will have a *__dict__*\n unless they also define *__slots__* (which must only contain names\n of any *additional* slots).\n\n* If a class defines a slot also defined in a base class, the instance\n variable defined by the base class slot is inaccessible (except by\n retrieving its descriptor directly from the base class). This\n renders the meaning of the program undefined. In the future, a\n check may be added to prevent this.\n\n* Nonempty *__slots__* does not work for classes derived from\n "variable-length" built-in types such as ``int``, ``str`` and\n ``tuple``.\n\n* Any non-string iterable may be assigned to *__slots__*. Mappings may\n also be used; however, in the future, special meaning may be\n assigned to the values corresponding to each key.\n\n* *__class__* assignment works only if both classes have the same\n *__slots__*.\n', 'attribute-references': '\nAttribute references\n********************\n\nAn attribute reference is a primary followed by a period and a name:\n\n attributeref ::= primary "." identifier\n\nThe primary must evaluate to an object of a type that supports\nattribute references, which most objects do. This object is then\nasked to produce the attribute whose name is the identifier (which can\nbe customized by overriding the ``__getattr__()`` method). If this\nattribute is not available, the exception ``AttributeError`` is\nraised. Otherwise, the type and value of the object produced is\ndetermined by the object. Multiple evaluations of the same attribute\nreference may yield different objects.\n', - 'augassign': '\nAugmented assignment statements\n*******************************\n\nAugmented assignment is the combination, in a single statement, of a\nbinary operation and an assignment statement:\n\n augmented_assignment_stmt ::= augtarget augop (expression_list | yield_expression)\n augtarget ::= identifier | attributeref | subscription | slicing\n augop ::= "+=" | "-=" | "*=" | "/=" | "//=" | "%=" | "**="\n | ">>=" | "<<=" | "&=" | "^=" | "|="\n\n(See section *Primaries* for the syntax definitions for the last three\nsymbols.)\n\nAn augmented assignment evaluates the target (which, unlike normal\nassignment statements, cannot be an unpacking) and the expression\nlist, performs the binary operation specific to the type of assignment\non the two operands, and assigns the result to the original target.\nThe target is only evaluated once.\n\nAn augmented assignment expression like ``x += 1`` can be rewritten as\n``x = x + 1`` to achieve a similar, but not exactly equal effect. In\nthe augmented version, ``x`` is only evaluated once. Also, when\npossible, the actual operation is performed *in-place*, meaning that\nrather than creating a new object and assigning that to the target,\nthe old object is modified instead.\n\nWith the exception of assigning to tuples and multiple targets in a\nsingle statement, the assignment done by augmented assignment\nstatements is handled the same way as normal assignments. Similarly,\nwith the exception of the possible *in-place* behavior, the binary\noperation performed by augmented assignment is the same as the normal\nbinary operations.\n\nFor targets which are attribute references, the initial value is\nretrieved with a ``getattr()`` and the result is assigned with a\n``setattr()``. Notice that the two methods do not necessarily refer\nto the same variable. When ``getattr()`` refers to a class variable,\n``setattr()`` still writes to an instance variable. For example:\n\n class A:\n x = 3 # class variable\n a = A()\n a.x += 1 # writes a.x as 4 leaving A.x as 3\n', + 'augassign': '\nAugmented assignment statements\n*******************************\n\nAugmented assignment is the combination, in a single statement, of a\nbinary operation and an assignment statement:\n\n augmented_assignment_stmt ::= augtarget augop (expression_list | yield_expression)\n augtarget ::= identifier | attributeref | subscription | slicing\n augop ::= "+=" | "-=" | "*=" | "/=" | "//=" | "%=" | "**="\n | ">>=" | "<<=" | "&=" | "^=" | "|="\n\n(See section *Primaries* for the syntax definitions for the last three\nsymbols.)\n\nAn augmented assignment evaluates the target (which, unlike normal\nassignment statements, cannot be an unpacking) and the expression\nlist, performs the binary operation specific to the type of assignment\non the two operands, and assigns the result to the original target.\nThe target is only evaluated once.\n\nAn augmented assignment expression like ``x += 1`` can be rewritten as\n``x = x + 1`` to achieve a similar, but not exactly equal effect. In\nthe augmented version, ``x`` is only evaluated once. Also, when\npossible, the actual operation is performed *in-place*, meaning that\nrather than creating a new object and assigning that to the target,\nthe old object is modified instead.\n\nWith the exception of assigning to tuples and multiple targets in a\nsingle statement, the assignment done by augmented assignment\nstatements is handled the same way as normal assignments. Similarly,\nwith the exception of the possible *in-place* behavior, the binary\noperation performed by augmented assignment is the same as the normal\nbinary operations.\n\nFor targets which are attribute references, the same *caveat about\nclass and instance attributes* applies as for regular assignments.\n', 'binary': '\nBinary arithmetic operations\n****************************\n\nThe binary arithmetic operations have the conventional priority\nlevels. Note that some of these operations also apply to certain non-\nnumeric types. Apart from the power operator, there are only two\nlevels, one for multiplicative operators and one for additive\noperators:\n\n m_expr ::= u_expr | m_expr "*" u_expr | m_expr "//" u_expr | m_expr "/" u_expr\n | m_expr "%" u_expr\n a_expr ::= m_expr | a_expr "+" m_expr | a_expr "-" m_expr\n\nThe ``*`` (multiplication) operator yields the product of its\narguments. The arguments must either both be numbers, or one argument\nmust be an integer and the other must be a sequence. In the former\ncase, the numbers are converted to a common type and then multiplied\ntogether. In the latter case, sequence repetition is performed; a\nnegative repetition factor yields an empty sequence.\n\nThe ``/`` (division) and ``//`` (floor division) operators yield the\nquotient of their arguments. The numeric arguments are first\nconverted to a common type. Integer division yields a float, while\nfloor division of integers results in an integer; the result is that\nof mathematical division with the \'floor\' function applied to the\nresult. Division by zero raises the ``ZeroDivisionError`` exception.\n\nThe ``%`` (modulo) operator yields the remainder from the division of\nthe first argument by the second. The numeric arguments are first\nconverted to a common type. A zero right argument raises the\n``ZeroDivisionError`` exception. The arguments may be floating point\nnumbers, e.g., ``3.14%0.7`` equals ``0.34`` (since ``3.14`` equals\n``4*0.7 + 0.34``.) The modulo operator always yields a result with\nthe same sign as its second operand (or zero); the absolute value of\nthe result is strictly smaller than the absolute value of the second\noperand [1].\n\nThe floor division and modulo operators are connected by the following\nidentity: ``x == (x//y)*y + (x%y)``. Floor division and modulo are\nalso connected with the built-in function ``divmod()``: ``divmod(x, y)\n== (x//y, x%y)``. [2].\n\nIn addition to performing the modulo operation on numbers, the ``%``\noperator is also overloaded by string objects to perform old-style\nstring formatting (also known as interpolation). The syntax for\nstring formatting is described in the Python Library Reference,\nsection *Old String Formatting Operations*.\n\nThe floor division operator, the modulo operator, and the ``divmod()``\nfunction are not defined for complex numbers. Instead, convert to a\nfloating point number using the ``abs()`` function if appropriate.\n\nThe ``+`` (addition) operator yields the sum of its arguments. The\narguments must either both be numbers or both sequences of the same\ntype. In the former case, the numbers are converted to a common type\nand then added together. In the latter case, the sequences are\nconcatenated.\n\nThe ``-`` (subtraction) operator yields the difference of its\narguments. The numeric arguments are first converted to a common\ntype.\n', 'bitwise': '\nBinary bitwise operations\n*************************\n\nEach of the three bitwise operations has a different priority level:\n\n and_expr ::= shift_expr | and_expr "&" shift_expr\n xor_expr ::= and_expr | xor_expr "^" and_expr\n or_expr ::= xor_expr | or_expr "|" xor_expr\n\nThe ``&`` operator yields the bitwise AND of its arguments, which must\nbe integers.\n\nThe ``^`` operator yields the bitwise XOR (exclusive OR) of its\narguments, which must be integers.\n\nThe ``|`` operator yields the bitwise (inclusive) OR of its arguments,\nwhich must be integers.\n', 'bltin-code-objects': '\nCode Objects\n************\n\nCode objects are used by the implementation to represent "pseudo-\ncompiled" executable Python code such as a function body. They differ\nfrom function objects because they don\'t contain a reference to their\nglobal execution environment. Code objects are returned by the built-\nin ``compile()`` function and can be extracted from function objects\nthrough their ``__code__`` attribute. See also the ``code`` module.\n\nA code object can be executed or evaluated by passing it (instead of a\nsource string) to the ``exec()`` or ``eval()`` built-in functions.\n\nSee *The standard type hierarchy* for more information.\n', 'bltin-ellipsis-object': '\nThe Ellipsis Object\n*******************\n\nThis object is commonly used by slicing (see *Slicings*). It supports\nno special operations. There is exactly one ellipsis object, named\n``Ellipsis`` (a built-in name).\n\nIt is written as ``Ellipsis`` or ``...``.\n', - 'bltin-file-objects': '\nFile Objects\n************\n\nFile objects are implemented using C\'s ``stdio`` package and can be\ncreated with the built-in ``open()`` function. File objects are also\nreturned by some other built-in functions and methods, such as\n``os.popen()`` and ``os.fdopen()`` and the ``makefile()`` method of\nsocket objects. Temporary files can be created using the ``tempfile``\nmodule, and high-level file operations such as copying, moving, and\ndeleting files and directories can be achieved with the ``shutil``\nmodule.\n\nWhen a file operation fails for an I/O-related reason, the exception\n``IOError`` is raised. This includes situations where the operation\nis not defined for some reason, like ``seek()`` on a tty device or\nwriting a file opened for reading.\n\nFiles have the following methods:\n\nfile.close()\n\n Close the file. A closed file cannot be read or written any more.\n Any operation which requires that the file be open will raise a\n ``ValueError`` after the file has been closed. Calling ``close()``\n more than once is allowed.\n\n You can avoid having to call this method explicitly if you use the\n ``with`` statement. For example, the following code will\n automatically close *f* when the ``with`` block is exited:\n\n from __future__ import with_statement # This isn\'t required in Python 2.6\n\n with open("hello.txt") as f:\n for line in f:\n print(line)\n\n In older versions of Python, you would have needed to do this to\n get the same effect:\n\n f = open("hello.txt")\n try:\n for line in f:\n print(line)\n finally:\n f.close()\n\n Note: Not all "file-like" types in Python support use as a context\n manager for the ``with`` statement. If your code is intended to\n work with any file-like object, you can use the function\n ``contextlib.closing()`` instead of using the object directly.\n\nfile.flush()\n\n Flush the internal buffer, like ``stdio``\'s ``fflush()``. This may\n be a no-op on some file-like objects.\n\n Note: ``flush()`` does not necessarily write the file\'s data to disk.\n Use ``flush()`` followed by ``os.fsync()`` to ensure this\n behavior.\n\nfile.fileno()\n\n Return the integer "file descriptor" that is used by the underlying\n implementation to request I/O operations from the operating system.\n This can be useful for other, lower level interfaces that use file\n descriptors, such as the ``fcntl`` module or ``os.read()`` and\n friends.\n\n Note: File-like objects which do not have a real file descriptor should\n *not* provide this method!\n\nfile.isatty()\n\n Return ``True`` if the file is connected to a tty(-like) device,\n else ``False``.\n\n Note: If a file-like object is not associated with a real file, this\n method should *not* be implemented.\n\nfile.__next__()\n\n A file object is its own iterator, for example ``iter(f)`` returns\n *f* (unless *f* is closed). When a file is used as an iterator,\n typically in a ``for`` loop (for example, ``for line in f:\n print(line)``), the ``__next__()`` method is called repeatedly.\n This method returns the next input line, or raises\n ``StopIteration`` when EOF is hit when the file is open for reading\n (behavior is undefined when the file is open for writing). In\n order to make a ``for`` loop the most efficient way of looping over\n the lines of a file (a very common operation), the ``__next__()``\n method uses a hidden read-ahead buffer. As a consequence of using\n a read-ahead buffer, combining ``__next__()`` with other file\n methods (like ``readline()``) does not work right. However, using\n ``seek()`` to reposition the file to an absolute position will\n flush the read-ahead buffer.\n\nfile.read([size])\n\n Read at most *size* bytes from the file (less if the read hits EOF\n before obtaining *size* bytes). If the *size* argument is negative\n or omitted, read all data until EOF is reached. The bytes are\n returned as a string object. An empty string is returned when EOF\n is encountered immediately. (For certain files, like ttys, it\n makes sense to continue reading after an EOF is hit.) Note that\n this method may call the underlying C function ``fread()`` more\n than once in an effort to acquire as close to *size* bytes as\n possible. Also note that when in non-blocking mode, less data than\n was requested may be returned, even if no *size* parameter was\n given.\n\nfile.readline([size])\n\n Read one entire line from the file. A trailing newline character\n is kept in the string (but may be absent when a file ends with an\n incomplete line). [5] If the *size* argument is present and non-\n negative, it is a maximum byte count (including the trailing\n newline) and an incomplete line may be returned. An empty string is\n returned *only* when EOF is encountered immediately.\n\n Note: Unlike ``stdio``\'s ``fgets()``, the returned string contains null\n characters (``\'\\0\'``) if they occurred in the input.\n\nfile.readlines([sizehint])\n\n Read until EOF using ``readline()`` and return a list containing\n the lines thus read. If the optional *sizehint* argument is\n present, instead of reading up to EOF, whole lines totalling\n approximately *sizehint* bytes (possibly after rounding up to an\n internal buffer size) are read. Objects implementing a file-like\n interface may choose to ignore *sizehint* if it cannot be\n implemented, or cannot be implemented efficiently.\n\nfile.seek(offset[, whence])\n\n Set the file\'s current position, like ``stdio``\'s ``fseek()``. The\n *whence* argument is optional and defaults to ``os.SEEK_SET`` or\n ``0`` (absolute file positioning); other values are ``os.SEEK_CUR``\n or ``1`` (seek relative to the current position) and\n ``os.SEEK_END`` or ``2`` (seek relative to the file\'s end). There\n is no return value.\n\n For example, ``f.seek(2, os.SEEK_CUR)`` advances the position by\n two and ``f.seek(-3, os.SEEK_END)`` sets the position to the third\n to last.\n\n Note that if the file is opened for appending (mode ``\'a\'`` or\n ``\'a+\'``), any ``seek()`` operations will be undone at the next\n write. If the file is only opened for writing in append mode (mode\n ``\'a\'``), this method is essentially a no-op, but it remains useful\n for files opened in append mode with reading enabled (mode\n ``\'a+\'``). If the file is opened in text mode (without ``\'b\'``),\n only offsets returned by ``tell()`` are legal. Use of other\n offsets causes undefined behavior.\n\n Note that not all file objects are seekable.\n\nfile.tell()\n\n Return the file\'s current position, like ``stdio``\'s ``ftell()``.\n\n Note: On Windows, ``tell()`` can return illegal values (after an\n ``fgets()``) when reading files with Unix-style line-endings. Use\n binary mode (``\'rb\'``) to circumvent this problem.\n\nfile.truncate([size])\n\n Truncate the file\'s size. If the optional *size* argument is\n present, the file is truncated to (at most) that size. The size\n defaults to the current position. The current file position is not\n changed. Note that if a specified size exceeds the file\'s current\n size, the result is platform-dependent: possibilities include that\n the file may remain unchanged, increase to the specified size as if\n zero-filled, or increase to the specified size with undefined new\n content. Availability: Windows, many Unix variants.\n\nfile.write(str)\n\n Write a string to the file. Due to buffering, the string may not\n actually show up in the file until the ``flush()`` or ``close()``\n method is called.\n\n The meaning of the return value is not defined for every file-like\n object. Some (mostly low-level) file-like objects may return the\n number of bytes actually written, others return ``None``.\n\nfile.writelines(sequence)\n\n Write a sequence of strings to the file. The sequence can be any\n iterable object producing strings, typically a list of strings.\n There is no return value. (The name is intended to match\n ``readlines()``; ``writelines()`` does not add line separators.)\n\nFiles support the iterator protocol. Each iteration returns the same\nresult as ``file.readline()``, and iteration ends when the\n``readline()`` method returns an empty string.\n\nFile objects also offer a number of other interesting attributes.\nThese are not required for file-like objects, but should be\nimplemented if they make sense for the particular object.\n\nfile.closed\n\n bool indicating the current state of the file object. This is a\n read-only attribute; the ``close()`` method changes the value. It\n may not be available on all file-like objects.\n\nfile.encoding\n\n The encoding that this file uses. When strings are written to a\n file, they will be converted to byte strings using this encoding.\n In addition, when the file is connected to a terminal, the\n attribute gives the encoding that the terminal is likely to use\n (that information might be incorrect if the user has misconfigured\n the terminal). The attribute is read-only and may not be present\n on all file-like objects. It may also be ``None``, in which case\n the file uses the system default encoding for converting strings.\n\nfile.errors\n\n The Unicode error handler used along with the encoding.\n\nfile.mode\n\n The I/O mode for the file. If the file was created using the\n ``open()`` built-in function, this will be the value of the *mode*\n parameter. This is a read-only attribute and may not be present on\n all file-like objects.\n\nfile.name\n\n If the file object was created using ``open()``, the name of the\n file. Otherwise, some string that indicates the source of the file\n object, of the form ``<...>``. This is a read-only attribute and\n may not be present on all file-like objects.\n\nfile.newlines\n\n If Python was built with the *--with-universal-newlines* option to\n **configure** (the default) this read-only attribute exists, and\n for files opened in universal newline read mode it keeps track of\n the types of newlines encountered while reading the file. The\n values it can take are ``\'\\r\'``, ``\'\\n\'``, ``\'\\r\\n\'``, ``None``\n (unknown, no newlines read yet) or a tuple containing all the\n newline types seen, to indicate that multiple newline conventions\n were encountered. For files not opened in universal newline read\n mode the value of this attribute will be ``None``.\n', 'bltin-null-object': "\nThe Null Object\n***************\n\nThis object is returned by functions that don't explicitly return a\nvalue. It supports no special operations. There is exactly one null\nobject, named ``None`` (a built-in name).\n\nIt is written as ``None``.\n", 'bltin-type-objects': "\nType Objects\n************\n\nType objects represent the various object types. An object's type is\naccessed by the built-in function ``type()``. There are no special\noperations on types. The standard module ``types`` defines names for\nall standard built-in types.\n\nTypes are written like this: ````.\n", - 'booleans': '\nBoolean operations\n******************\n\nBoolean operations have the lowest priority of all Python operations:\n\n expression ::= conditional_expression | lambda_form\n expression_nocond ::= or_test | lambda_form_nocond\n conditional_expression ::= or_test ["if" or_test "else" expression]\n or_test ::= and_test | or_test "or" and_test\n and_test ::= not_test | and_test "and" not_test\n not_test ::= comparison | "not" not_test\n\nIn the context of Boolean operations, and also when expressions are\nused by control flow statements, the following values are interpreted\nas false: ``False``, ``None``, numeric zero of all types, and empty\nstrings and containers (including strings, tuples, lists,\ndictionaries, sets and frozensets). All other values are interpreted\nas true. User-defined objects can customize their truth value by\nproviding a ``__bool__()`` method.\n\nThe operator ``not`` yields ``True`` if its argument is false,\n``False`` otherwise.\n\nThe expression ``x if C else y`` first evaluates *C* (*not* *x*); if\n*C* is true, *x* is evaluated and its value is returned; otherwise,\n*y* is evaluated and its value is returned.\n\nThe expression ``x and y`` first evaluates *x*; if *x* is false, its\nvalue is returned; otherwise, *y* is evaluated and the resulting value\nis returned.\n\nThe expression ``x or y`` first evaluates *x*; if *x* is true, its\nvalue is returned; otherwise, *y* is evaluated and the resulting value\nis returned.\n\n(Note that neither ``and`` nor ``or`` restrict the value and type they\nreturn to ``False`` and ``True``, but rather return the last evaluated\nargument. This is sometimes useful, e.g., if ``s`` is a string that\nshould be replaced by a default value if it is empty, the expression\n``s or \'foo\'`` yields the desired value. Because ``not`` has to\ninvent a value anyway, it does not bother to return a value of the\nsame type as its argument, so e.g., ``not \'foo\'`` yields ``False``,\nnot ``\'\'``.)\n', + 'booleans': '\nBoolean operations\n******************\n\n or_test ::= and_test | or_test "or" and_test\n and_test ::= not_test | and_test "and" not_test\n not_test ::= comparison | "not" not_test\n\nIn the context of Boolean operations, and also when expressions are\nused by control flow statements, the following values are interpreted\nas false: ``False``, ``None``, numeric zero of all types, and empty\nstrings and containers (including strings, tuples, lists,\ndictionaries, sets and frozensets). All other values are interpreted\nas true. User-defined objects can customize their truth value by\nproviding a ``__bool__()`` method.\n\nThe operator ``not`` yields ``True`` if its argument is false,\n``False`` otherwise.\n\nThe expression ``x and y`` first evaluates *x*; if *x* is false, its\nvalue is returned; otherwise, *y* is evaluated and the resulting value\nis returned.\n\nThe expression ``x or y`` first evaluates *x*; if *x* is true, its\nvalue is returned; otherwise, *y* is evaluated and the resulting value\nis returned.\n\n(Note that neither ``and`` nor ``or`` restrict the value and type they\nreturn to ``False`` and ``True``, but rather return the last evaluated\nargument. This is sometimes useful, e.g., if ``s`` is a string that\nshould be replaced by a default value if it is empty, the expression\n``s or \'foo\'`` yields the desired value. Because ``not`` has to\ninvent a value anyway, it does not bother to return a value of the\nsame type as its argument, so e.g., ``not \'foo\'`` yields ``False``,\nnot ``\'\'``.)\n', 'break': '\nThe ``break`` statement\n***********************\n\n break_stmt ::= "break"\n\n``break`` may only occur syntactically nested in a ``for`` or\n``while`` loop, but not nested in a function or class definition\nwithin that loop.\n\nIt terminates the nearest enclosing loop, skipping the optional\n``else`` clause if the loop has one.\n\nIf a ``for`` loop is terminated by ``break``, the loop control target\nkeeps its current value.\n\nWhen ``break`` passes control out of a ``try`` statement with a\n``finally`` clause, that ``finally`` clause is executed before really\nleaving the loop.\n', 'callable-types': '\nEmulating callable objects\n**************************\n\nobject.__call__(self[, args...])\n\n Called when the instance is "called" as a function; if this method\n is defined, ``x(arg1, arg2, ...)`` is a shorthand for\n ``x.__call__(arg1, arg2, ...)``.\n', - 'calls': '\nCalls\n*****\n\nA call calls a callable object (e.g., a function) with a possibly\nempty series of arguments:\n\n call ::= primary "(" [argument_list [","] | comprehension] ")"\n argument_list ::= positional_arguments ["," keyword_arguments]\n ["," "*" expression] ["," keyword_arguments]\n ["," "**" expression]\n | keyword_arguments ["," "*" expression]\n ["," keyword_arguments] ["," "**" expression]\n | "*" expression ["," keyword_arguments] ["," "**" expression]\n | "**" expression\n positional_arguments ::= expression ("," expression)*\n keyword_arguments ::= keyword_item ("," keyword_item)*\n keyword_item ::= identifier "=" expression\n\nA trailing comma may be present after the positional and keyword\narguments but does not affect the semantics.\n\nThe primary must evaluate to a callable object (user-defined\nfunctions, built-in functions, methods of built-in objects, class\nobjects, methods of class instances, and all objects having a\n``__call__()`` method are callable). All argument expressions are\nevaluated before the call is attempted. Please refer to section\n*Function definitions* for the syntax of formal parameter lists.\n\nIf keyword arguments are present, they are first converted to\npositional arguments, as follows. First, a list of unfilled slots is\ncreated for the formal parameters. If there are N positional\narguments, they are placed in the first N slots. Next, for each\nkeyword argument, the identifier is used to determine the\ncorresponding slot (if the identifier is the same as the first formal\nparameter name, the first slot is used, and so on). If the slot is\nalready filled, a ``TypeError`` exception is raised. Otherwise, the\nvalue of the argument is placed in the slot, filling it (even if the\nexpression is ``None``, it fills the slot). When all arguments have\nbeen processed, the slots that are still unfilled are filled with the\ncorresponding default value from the function definition. (Default\nvalues are calculated, once, when the function is defined; thus, a\nmutable object such as a list or dictionary used as default value will\nbe shared by all calls that don\'t specify an argument value for the\ncorresponding slot; this should usually be avoided.) If there are any\nunfilled slots for which no default value is specified, a\n``TypeError`` exception is raised. Otherwise, the list of filled\nslots is used as the argument list for the call.\n\nNote: An implementation may provide builtin functions whose positional\n parameters do not have names, even if they are \'named\' for the\n purpose of documentation, and which therefore cannot be supplied by\n keyword. In CPython, this is the case for functions implemented in\n C that use ``PyArg_ParseTuple()`` to parse their arguments.\n\nIf there are more positional arguments than there are formal parameter\nslots, a ``TypeError`` exception is raised, unless a formal parameter\nusing the syntax ``*identifier`` is present; in this case, that formal\nparameter receives a tuple containing the excess positional arguments\n(or an empty tuple if there were no excess positional arguments).\n\nIf any keyword argument does not correspond to a formal parameter\nname, a ``TypeError`` exception is raised, unless a formal parameter\nusing the syntax ``**identifier`` is present; in this case, that\nformal parameter receives a dictionary containing the excess keyword\narguments (using the keywords as keys and the argument values as\ncorresponding values), or a (new) empty dictionary if there were no\nexcess keyword arguments.\n\nIf the syntax ``*expression`` appears in the function call,\n``expression`` must evaluate to a sequence. Elements from this\nsequence are treated as if they were additional positional arguments;\nif there are positional arguments *x1*,..., *xN*, and ``expression``\nevaluates to a sequence *y1*, ..., *yM*, this is equivalent to a call\nwith M+N positional arguments *x1*, ..., *xN*, *y1*, ..., *yM*.\n\nA consequence of this is that although the ``*expression`` syntax may\nappear *after* some keyword arguments, it is processed *before* the\nkeyword arguments (and the ``**expression`` argument, if any -- see\nbelow). So:\n\n >>> def f(a, b):\n ... print(a, b)\n ...\n >>> f(b=1, *(2,))\n 2 1\n >>> f(a=1, *(2,))\n Traceback (most recent call last):\n File "", line 1, in ?\n TypeError: f() got multiple values for keyword argument \'a\'\n >>> f(1, *(2,))\n 1 2\n\nIt is unusual for both keyword arguments and the ``*expression``\nsyntax to be used in the same call, so in practice this confusion does\nnot arise.\n\nIf the syntax ``**expression`` appears in the function call,\n``expression`` must evaluate to a mapping, the contents of which are\ntreated as additional keyword arguments. In the case of a keyword\nappearing in both ``expression`` and as an explicit keyword argument,\na ``TypeError`` exception is raised.\n\nFormal parameters using the syntax ``*identifier`` or ``**identifier``\ncannot be used as positional argument slots or as keyword argument\nnames.\n\nA call always returns some value, possibly ``None``, unless it raises\nan exception. How this value is computed depends on the type of the\ncallable object.\n\nIf it is---\n\na user-defined function:\n The code block for the function is executed, passing it the\n argument list. The first thing the code block will do is bind the\n formal parameters to the arguments; this is described in section\n *Function definitions*. When the code block executes a ``return``\n statement, this specifies the return value of the function call.\n\na built-in function or method:\n The result is up to the interpreter; see *Built-in Functions* for\n the descriptions of built-in functions and methods.\n\na class object:\n A new instance of that class is returned.\n\na class instance method:\n The corresponding user-defined function is called, with an argument\n list that is one longer than the argument list of the call: the\n instance becomes the first argument.\n\na class instance:\n The class must define a ``__call__()`` method; the effect is then\n the same as if that method was called.\n', - 'class': '\nClass definitions\n*****************\n\nA class definition defines a class object (see section *The standard\ntype hierarchy*):\n\n classdef ::= [decorators] "class" classname [inheritance] ":" suite\n inheritance ::= "(" [expression_list] ")"\n classname ::= identifier\n\nA class definition is an executable statement. It first evaluates the\ninheritance list, if present. Each item in the inheritance list\nshould evaluate to a class object or class type which allows\nsubclassing. The class\'s suite is then executed in a new execution\nframe (see section *Naming and binding*), using a newly created local\nnamespace and the original global namespace. (Usually, the suite\ncontains only function definitions.) When the class\'s suite finishes\nexecution, its execution frame is discarded but its local namespace is\nsaved. [4] A class object is then created using the inheritance list\nfor the base classes and the saved local namespace for the attribute\ndictionary. The class name is bound to this class object in the\noriginal local namespace.\n\nClasses can also be decorated; as with functions,\n\n @f1(arg)\n @f2\n class Foo: pass\n\nis equivalent to\n\n class Foo: pass\n Foo = f1(arg)(f2(Foo))\n\n**Programmer\'s note:** Variables defined in the class definition are\nclass variables; they are shared by instances. Instance variables can\nbe set in a method with ``self.name = value``. Both class and\ninstance variables are accessible through the notation\n"``self.name``", and an instance variable hides a class variable with\nthe same name when accessed in this way. Class variables can be used\nas defaults for instance variables, but using mutable values there can\nlead to unexpected results. Descriptors can be used to create\ninstance variables with different implementation details.\n\nSee also:\n\n **PEP 3129** - Class Decorators\n\nClass definitions, like function definitions, may be wrapped by one or\nmore *decorator* expressions. The evaluation rules for the decorator\nexpressions are the same as for functions. The result must be a class\nobject, which is then bound to the class name.\n\n-[ Footnotes ]-\n\n[1] The exception is propagated to the invocation stack only if there\n is no ``finally`` clause that negates the exception.\n\n[2] Currently, control "flows off the end" except in the case of an\n exception or the execution of a ``return``, ``continue``, or\n ``break`` statement.\n\n[3] A string literal appearing as the first statement in the function\n body is transformed into the function\'s ``__doc__`` attribute and\n therefore the function\'s *docstring*.\n\n[4] A string literal appearing as the first statement in the class\n body is transformed into the namespace\'s ``__doc__`` item and\n therefore the class\'s *docstring*.\n', - 'comparisons': '\nComparisons\n***********\n\nUnlike C, all comparison operations in Python have the same priority,\nwhich is lower than that of any arithmetic, shifting or bitwise\noperation. Also unlike C, expressions like ``a < b < c`` have the\ninterpretation that is conventional in mathematics:\n\n comparison ::= or_expr ( comp_operator or_expr )*\n comp_operator ::= "<" | ">" | "==" | ">=" | "<=" | "!="\n | "is" ["not"] | ["not"] "in"\n\nComparisons yield boolean values: ``True`` or ``False``.\n\nComparisons can be chained arbitrarily, e.g., ``x < y <= z`` is\nequivalent to ``x < y and y <= z``, except that ``y`` is evaluated\nonly once (but in both cases ``z`` is not evaluated at all when ``x <\ny`` is found to be false).\n\nFormally, if *a*, *b*, *c*, ..., *y*, *z* are expressions and *op1*,\n*op2*, ..., *opN* are comparison operators, then ``a op1 b op2 c ... y\nopN z`` is equivalent to ``a op1 b and b op2 c and ... y opN z``,\nexcept that each expression is evaluated at most once.\n\nNote that ``a op1 b op2 c`` doesn\'t imply any kind of comparison\nbetween *a* and *c*, so that, e.g., ``x < y > z`` is perfectly legal\n(though perhaps not pretty).\n\nThe operators ``<``, ``>``, ``==``, ``>=``, ``<=``, and ``!=`` compare\nthe values of two objects. The objects need not have the same type.\nIf both are numbers, they are converted to a common type. Otherwise,\nthe ``==`` and ``!=`` operators *always* consider objects of different\ntypes to be unequal, while the ``<``, ``>``, ``>=`` and ``<=``\noperators raise a ``TypeError`` when comparing objects of different\ntypes that do not implement these operators for the given pair of\ntypes. You can control comparison behavior of objects of non-builtin\ntypes by defining rich comparison methods like ``__gt__()``, described\nin section *Basic customization*.\n\nComparison of objects of the same type depends on the type:\n\n* Numbers are compared arithmetically.\n\n* The values ``float(\'NaN\')`` and ``Decimal(\'NaN\')`` are special. The\n are identical to themselves, ``x is x`` but are not equal to\n themselves, ``x != x``. Additionally, comparing any value to a\n not-a-number value will return ``False``. For example, both ``3 <\n float(\'NaN\')`` and ``float(\'NaN\') < 3`` will return ``False``.\n\n* Bytes objects are compared lexicographically using the numeric\n values of their elements.\n\n* Strings are compared lexicographically using the numeric equivalents\n (the result of the built-in function ``ord()``) of their characters.\n [3] String and bytes object can\'t be compared!\n\n* Tuples and lists are compared lexicographically using comparison of\n corresponding elements. This means that to compare equal, each\n element must compare equal and the two sequences must be of the same\n type and have the same length.\n\n If not equal, the sequences are ordered the same as their first\n differing elements. For example, ``[1,2,x] <= [1,2,y]`` has the\n same value as ``x <= y``. If the corresponding element does not\n exist, the shorter sequence is ordered first (for example, ``[1,2] <\n [1,2,3]``).\n\n* Mappings (dictionaries) compare equal if and only if their sorted\n ``(key, value)`` lists compare equal. [4] Outcomes other than\n equality are resolved consistently, but are not otherwise defined.\n [5]\n\n* Sets and frozensets define comparison operators to mean subset and\n superset tests. Those relations do not define total orderings (the\n two sets ``{1,2}`` and {2,3} are not equal, nor subsets of one\n another, nor supersets of one another). Accordingly, sets are not\n appropriate arguments for functions which depend on total ordering.\n For example, ``min()``, ``max()``, and ``sorted()`` produce\n undefined results given a list of sets as inputs.\n\n* Most other objects of builtin types compare unequal unless they are\n the same object; the choice whether one object is considered smaller\n or larger than another one is made arbitrarily but consistently\n within one execution of a program.\n\nComparison of objects of the differing types depends on whether either\nof the types provide explicit support for the comparison. Most\nnumeric types can be compared with one another, but comparisons of\n``float`` and ``Decimal`` are not supported to avoid the inevitable\nconfusion arising from representation issues such as ``float(\'1.1\')``\nbeing inexactly represented and therefore not exactly equal to\n``Decimal(\'1.1\')`` which is. When cross-type comparison is not\nsupported, the comparison method returns ``NotImplemented``. This can\ncreate the illusion of non-transitivity between supported cross-type\ncomparisons and unsupported comparisons. For example, ``Decimal(2) ==\n2`` and *2 == float(2)`* but ``Decimal(2) != float(2)``.\n\nThe operators ``in`` and ``not in`` test for membership. ``x in s``\nevaluates to true if *x* is a member of *s*, and false otherwise. ``x\nnot in s`` returns the negation of ``x in s``. All built-in sequences\nand set types support this as well as dictionary, for which ``in``\ntests whether a the dictionary has a given key. For container types\nsuch as list, tuple, set, frozenset, dict, or collections.deque, the\nexpression ``x in y`` is equivalent to ``any(x is e or x == e for val\ne in y)``.\n\nFor the string and bytes types, ``x in y`` is true if and only if *x*\nis a substring of *y*. An equivalent test is ``y.find(x) != -1``.\nEmpty strings are always considered to be a substring of any other\nstring, so ``"" in "abc"`` will return ``True``.\n\nFor user-defined classes which define the ``__contains__()`` method,\n``x in y`` is true if and only if ``y.__contains__(x)`` is true.\n\nFor user-defined classes which do not define ``__contains__()`` and do\ndefine ``__getitem__()``, ``x in y`` is true if and only if there is a\nnon-negative integer index *i* such that ``x == y[i]``, and all lower\ninteger indices do not raise ``IndexError`` exception. (If any other\nexception is raised, it is as if ``in`` raised that exception).\n\nThe operator ``not in`` is defined to have the inverse true value of\n``in``.\n\nThe operators ``is`` and ``is not`` test for object identity: ``x is\ny`` is true if and only if *x* and *y* are the same object. ``x is\nnot y`` yields the inverse truth value. [6]\n', - 'compound': '\nCompound statements\n*******************\n\nCompound statements contain (groups of) other statements; they affect\nor control the execution of those other statements in some way. In\ngeneral, compound statements span multiple lines, although in simple\nincarnations a whole compound statement may be contained in one line.\n\nThe ``if``, ``while`` and ``for`` statements implement traditional\ncontrol flow constructs. ``try`` specifies exception handlers and/or\ncleanup code for a group of statements, while the ``with`` statement\nallows the execution of initialization and finalization code around a\nblock of code. Function and class definitions are also syntactically\ncompound statements.\n\nCompound statements consist of one or more \'clauses.\' A clause\nconsists of a header and a \'suite.\' The clause headers of a\nparticular compound statement are all at the same indentation level.\nEach clause header begins with a uniquely identifying keyword and ends\nwith a colon. A suite is a group of statements controlled by a\nclause. A suite can be one or more semicolon-separated simple\nstatements on the same line as the header, following the header\'s\ncolon, or it can be one or more indented statements on subsequent\nlines. Only the latter form of suite can contain nested compound\nstatements; the following is illegal, mostly because it wouldn\'t be\nclear to which ``if`` clause a following ``else`` clause would belong:\n\n if test1: if test2: print(x)\n\nAlso note that the semicolon binds tighter than the colon in this\ncontext, so that in the following example, either all or none of the\n``print()`` calls are executed:\n\n if x < y < z: print(x); print(y); print(z)\n\nSummarizing:\n\n compound_stmt ::= if_stmt\n | while_stmt\n | for_stmt\n | try_stmt\n | with_stmt\n | funcdef\n | classdef\n suite ::= stmt_list NEWLINE | NEWLINE INDENT statement+ DEDENT\n statement ::= stmt_list NEWLINE | compound_stmt\n stmt_list ::= simple_stmt (";" simple_stmt)* [";"]\n\nNote that statements always end in a ``NEWLINE`` possibly followed by\na ``DEDENT``. Also note that optional continuation clauses always\nbegin with a keyword that cannot start a statement, thus there are no\nambiguities (the \'dangling ``else``\' problem is solved in Python by\nrequiring nested ``if`` statements to be indented).\n\nThe formatting of the grammar rules in the following sections places\neach clause on a separate line for clarity.\n\n\nThe ``if`` statement\n====================\n\nThe ``if`` statement is used for conditional execution:\n\n if_stmt ::= "if" expression ":" suite\n ( "elif" expression ":" suite )*\n ["else" ":" suite]\n\nIt selects exactly one of the suites by evaluating the expressions one\nby one until one is found to be true (see section *Boolean operations*\nfor the definition of true and false); then that suite is executed\n(and no other part of the ``if`` statement is executed or evaluated).\nIf all expressions are false, the suite of the ``else`` clause, if\npresent, is executed.\n\n\nThe ``while`` statement\n=======================\n\nThe ``while`` statement is used for repeated execution as long as an\nexpression is true:\n\n while_stmt ::= "while" expression ":" suite\n ["else" ":" suite]\n\nThis repeatedly tests the expression and, if it is true, executes the\nfirst suite; if the expression is false (which may be the first time\nit is tested) the suite of the ``else`` clause, if present, is\nexecuted and the loop terminates.\n\nA ``break`` statement executed in the first suite terminates the loop\nwithout executing the ``else`` clause\'s suite. A ``continue``\nstatement executed in the first suite skips the rest of the suite and\ngoes back to testing the expression.\n\n\nThe ``for`` statement\n=====================\n\nThe ``for`` statement is used to iterate over the elements of a\nsequence (such as a string, tuple or list) or other iterable object:\n\n for_stmt ::= "for" target_list "in" expression_list ":" suite\n ["else" ":" suite]\n\nThe expression list is evaluated once; it should yield an iterable\nobject. An iterator is created for the result of the\n``expression_list``. The suite is then executed once for each item\nprovided by the iterator, in the order of ascending indices. Each\nitem in turn is assigned to the target list using the standard rules\nfor assignments (see *Assignment statements*), and then the suite is\nexecuted. When the items are exhausted (which is immediately when the\nsequence is empty or an iterator raises a ``StopIteration``\nexception), the suite in the ``else`` clause, if present, is executed,\nand the loop terminates.\n\nA ``break`` statement executed in the first suite terminates the loop\nwithout executing the ``else`` clause\'s suite. A ``continue``\nstatement executed in the first suite skips the rest of the suite and\ncontinues with the next item, or with the ``else`` clause if there was\nno next item.\n\nThe suite may assign to the variable(s) in the target list; this does\nnot affect the next item assigned to it.\n\nNames in the target list are not deleted when the loop is finished,\nbut if the sequence is empty, it will not have been assigned to at all\nby the loop. Hint: the built-in function ``range()`` returns an\niterator of integers suitable to emulate the effect of Pascal\'s ``for\ni := a to b do``; e.g., ``list(range(3))`` returns the list ``[0, 1,\n2]``.\n\nNote: There is a subtlety when the sequence is being modified by the loop\n (this can only occur for mutable sequences, i.e. lists). An\n internal counter is used to keep track of which item is used next,\n and this is incremented on each iteration. When this counter has\n reached the length of the sequence the loop terminates. This means\n that if the suite deletes the current (or a previous) item from the\n sequence, the next item will be skipped (since it gets the index of\n the current item which has already been treated). Likewise, if the\n suite inserts an item in the sequence before the current item, the\n current item will be treated again the next time through the loop.\n This can lead to nasty bugs that can be avoided by making a\n temporary copy using a slice of the whole sequence, e.g.,\n\n for x in a[:]:\n if x < 0: a.remove(x)\n\n\nThe ``try`` statement\n=====================\n\nThe ``try`` statement specifies exception handlers and/or cleanup code\nfor a group of statements:\n\n try_stmt ::= try1_stmt | try2_stmt\n try1_stmt ::= "try" ":" suite\n ("except" [expression ["as" target]] ":" suite)+\n ["else" ":" suite]\n ["finally" ":" suite]\n try2_stmt ::= "try" ":" suite\n "finally" ":" suite\n\nThe ``except`` clause(s) specify one or more exception handlers. When\nno exception occurs in the ``try`` clause, no exception handler is\nexecuted. When an exception occurs in the ``try`` suite, a search for\nan exception handler is started. This search inspects the except\nclauses in turn until one is found that matches the exception. An\nexpression-less except clause, if present, must be last; it matches\nany exception. For an except clause with an expression, that\nexpression is evaluated, and the clause matches the exception if the\nresulting object is "compatible" with the exception. An object is\ncompatible with an exception if it is the class or a base class of the\nexception object or a tuple containing an item compatible with the\nexception.\n\nIf no except clause matches the exception, the search for an exception\nhandler continues in the surrounding code and on the invocation stack.\n[1]\n\nIf the evaluation of an expression in the header of an except clause\nraises an exception, the original search for a handler is canceled and\na search starts for the new exception in the surrounding code and on\nthe call stack (it is treated as if the entire ``try`` statement\nraised the exception).\n\nWhen a matching except clause is found, the exception is assigned to\nthe target specified after the ``as`` keyword in that except clause,\nif present, and the except clause\'s suite is executed. All except\nclauses must have an executable block. When the end of this block is\nreached, execution continues normally after the entire try statement.\n(This means that if two nested handlers exist for the same exception,\nand the exception occurs in the try clause of the inner handler, the\nouter handler will not handle the exception.)\n\nWhen an exception has been assigned using ``as target``, it is cleared\nat the end of the except clause. This is as if\n\n except E as N:\n foo\n\nwas translated to\n\n except E as N:\n try:\n foo\n finally:\n N = None\n del N\n\nThat means that you have to assign the exception to a different name\nif you want to be able to refer to it after the except clause. The\nreason for this is that with the traceback attached to them,\nexceptions will form a reference cycle with the stack frame, keeping\nall locals in that frame alive until the next garbage collection\noccurs.\n\nBefore an except clause\'s suite is executed, details about the\nexception are stored in the ``sys`` module and can be access via\n``sys.exc_info()``. ``sys.exc_info()`` returns a 3-tuple consisting\nof: ``exc_type``, the exception class; ``exc_value``, the exception\ninstance; ``exc_traceback``, a traceback object (see section *The\nstandard type hierarchy*) identifying the point in the program where\nthe exception occurred. ``sys.exc_info()`` values are restored to\ntheir previous values (before the call) when returning from a function\nthat handled an exception.\n\nThe optional ``else`` clause is executed if and when control flows off\nthe end of the ``try`` clause. [2] Exceptions in the ``else`` clause\nare not handled by the preceding ``except`` clauses.\n\nIf ``finally`` is present, it specifies a \'cleanup\' handler. The\n``try`` clause is executed, including any ``except`` and ``else``\nclauses. If an exception occurs in any of the clauses and is not\nhandled, the exception is temporarily saved. The ``finally`` clause is\nexecuted. If there is a saved exception, it is re-raised at the end\nof the ``finally`` clause. If the ``finally`` clause raises another\nexception or executes a ``return`` or ``break`` statement, the saved\nexception is lost. The exception information is not available to the\nprogram during execution of the ``finally`` clause.\n\nWhen a ``return``, ``break`` or ``continue`` statement is executed in\nthe ``try`` suite of a ``try``...``finally`` statement, the\n``finally`` clause is also executed \'on the way out.\' A ``continue``\nstatement is illegal in the ``finally`` clause. (The reason is a\nproblem with the current implementation --- this restriction may be\nlifted in the future).\n\nAdditional information on exceptions can be found in section\n*Exceptions*, and information on using the ``raise`` statement to\ngenerate exceptions may be found in section *The raise statement*.\n\n\nThe ``with`` statement\n======================\n\nThe ``with`` statement is used to wrap the execution of a block with\nmethods defined by a context manager (see section *With Statement\nContext Managers*). This allows common\n``try``...``except``...``finally`` usage patterns to be encapsulated\nfor convenient reuse.\n\n with_stmt ::= "with" with_item ("," with_item)* ":" suite\n with_item ::= expression ["as" target]\n\nThe execution of the ``with`` statement with one "item" proceeds as\nfollows:\n\n1. The context expression is evaluated to obtain a context manager.\n\n2. The context manager\'s ``__enter__()`` method is invoked.\n\n3. If a target was included in the ``with`` statement, the return\n value from ``__enter__()`` is assigned to it.\n\n Note: The ``with`` statement guarantees that if the ``__enter__()``\n method returns without an error, then ``__exit__()`` will always\n be called. Thus, if an error occurs during the assignment to the\n target list, it will be treated the same as an error occurring\n within the suite would be. See step 5 below.\n\n4. The suite is executed.\n\n5. The context manager\'s ``__exit__()`` method is invoked. If an\n exception caused the suite to be exited, its type, value, and\n traceback are passed as arguments to ``__exit__()``. Otherwise,\n three ``None`` arguments are supplied.\n\n If the suite was exited due to an exception, and the return value\n from the ``__exit__()`` method was false, the exception is\n reraised. If the return value was true, the exception is\n suppressed, and execution continues with the statement following\n the ``with`` statement.\n\n If the suite was exited for any reason other than an exception, the\n return value from ``__exit__()`` is ignored, and execution proceeds\n at the normal location for the kind of exit that was taken.\n\nWith more than one item, the context managers are processed as if\nmultiple ``with`` statements were nested:\n\n with A() as a, B() as b:\n suite\n\nis equivalent to\n\n with A() as a:\n with B() as b:\n suite\n\nChanged in version 3.1: Support for multiple context expressions.\n\nSee also:\n\n **PEP 0343** - The "with" statement\n The specification, background, and examples for the Python\n ``with`` statement.\n\n\nFunction definitions\n====================\n\nA function definition defines a user-defined function object (see\nsection *The standard type hierarchy*):\n\n funcdef ::= [decorators] "def" funcname "(" [parameter_list] ")" ["->" expression] ":" suite\n decorators ::= decorator+\n decorator ::= "@" dotted_name ["(" [argument_list [","]] ")"] NEWLINE\n dotted_name ::= identifier ("." identifier)*\n parameter_list ::= (defparameter ",")*\n ( "*" [parameter] ("," defparameter)*\n [, "**" parameter]\n | "**" parameter\n | defparameter [","] )\n parameter ::= identifier [":" expression]\n defparameter ::= parameter ["=" expression]\n funcname ::= identifier\n\nA function definition is an executable statement. Its execution binds\nthe function name in the current local namespace to a function object\n(a wrapper around the executable code for the function). This\nfunction object contains a reference to the current global namespace\nas the global namespace to be used when the function is called.\n\nThe function definition does not execute the function body; this gets\nexecuted only when the function is called. [3]\n\nA function definition may be wrapped by one or more *decorator*\nexpressions. Decorator expressions are evaluated when the function is\ndefined, in the scope that contains the function definition. The\nresult must be a callable, which is invoked with the function object\nas the only argument. The returned value is bound to the function name\ninstead of the function object. Multiple decorators are applied in\nnested fashion. For example, the following code\n\n @f1(arg)\n @f2\n def func(): pass\n\nis equivalent to\n\n def func(): pass\n func = f1(arg)(f2(func))\n\nWhen one or more parameters have the form *parameter* ``=``\n*expression*, the function is said to have "default parameter values."\nFor a parameter with a default value, the corresponding argument may\nbe omitted from a call, in which case the parameter\'s default value is\nsubstituted. If a parameter has a default value, all following\nparameters up until the "``*``" must also have a default value ---\nthis is a syntactic restriction that is not expressed by the grammar.\n\n**Default parameter values are evaluated when the function definition\nis executed.** This means that the expression is evaluated once, when\nthe function is defined, and that that same "pre-computed" value is\nused for each call. This is especially important to understand when a\ndefault parameter is a mutable object, such as a list or a dictionary:\nif the function modifies the object (e.g. by appending an item to a\nlist), the default value is in effect modified. This is generally not\nwhat was intended. A way around this is to use ``None`` as the\ndefault, and explicitly test for it in the body of the function, e.g.:\n\n def whats_on_the_telly(penguin=None):\n if penguin is None:\n penguin = []\n penguin.append("property of the zoo")\n return penguin\n\nFunction call semantics are described in more detail in section\n*Calls*. A function call always assigns values to all parameters\nmentioned in the parameter list, either from position arguments, from\nkeyword arguments, or from default values. If the form\n"``*identifier``" is present, it is initialized to a tuple receiving\nany excess positional parameters, defaulting to the empty tuple. If\nthe form "``**identifier``" is present, it is initialized to a new\ndictionary receiving any excess keyword arguments, defaulting to a new\nempty dictionary. Parameters after "``*``" or "``*identifier``" are\nkeyword-only parameters and may only be passed used keyword arguments.\n\nParameters may have annotations of the form "``: expression``"\nfollowing the parameter name. Any parameter may have an annotation\neven those of the form ``*identifier`` or ``**identifier``. Functions\nmay have "return" annotation of the form "``-> expression``" after the\nparameter list. These annotations can be any valid Python expression\nand are evaluated when the function definition is executed.\nAnnotations may be evaluated in a different order than they appear in\nthe source code. The presence of annotations does not change the\nsemantics of a function. The annotation values are available as\nvalues of a dictionary keyed by the parameters\' names in the\n``__annotations__`` attribute of the function object.\n\nIt is also possible to create anonymous functions (functions not bound\nto a name), for immediate use in expressions. This uses lambda forms,\ndescribed in section *Lambdas*. Note that the lambda form is merely a\nshorthand for a simplified function definition; a function defined in\na "``def``" statement can be passed around or assigned to another name\njust like a function defined by a lambda form. The "``def``" form is\nactually more powerful since it allows the execution of multiple\nstatements and annotations.\n\n**Programmer\'s note:** Functions are first-class objects. A "``def``"\nform executed inside a function definition defines a local function\nthat can be returned or passed around. Free variables used in the\nnested function can access the local variables of the function\ncontaining the def. See section *Naming and binding* for details.\n\n\nClass definitions\n=================\n\nA class definition defines a class object (see section *The standard\ntype hierarchy*):\n\n classdef ::= [decorators] "class" classname [inheritance] ":" suite\n inheritance ::= "(" [expression_list] ")"\n classname ::= identifier\n\nA class definition is an executable statement. It first evaluates the\ninheritance list, if present. Each item in the inheritance list\nshould evaluate to a class object or class type which allows\nsubclassing. The class\'s suite is then executed in a new execution\nframe (see section *Naming and binding*), using a newly created local\nnamespace and the original global namespace. (Usually, the suite\ncontains only function definitions.) When the class\'s suite finishes\nexecution, its execution frame is discarded but its local namespace is\nsaved. [4] A class object is then created using the inheritance list\nfor the base classes and the saved local namespace for the attribute\ndictionary. The class name is bound to this class object in the\noriginal local namespace.\n\nClasses can also be decorated; as with functions,\n\n @f1(arg)\n @f2\n class Foo: pass\n\nis equivalent to\n\n class Foo: pass\n Foo = f1(arg)(f2(Foo))\n\n**Programmer\'s note:** Variables defined in the class definition are\nclass variables; they are shared by instances. Instance variables can\nbe set in a method with ``self.name = value``. Both class and\ninstance variables are accessible through the notation\n"``self.name``", and an instance variable hides a class variable with\nthe same name when accessed in this way. Class variables can be used\nas defaults for instance variables, but using mutable values there can\nlead to unexpected results. Descriptors can be used to create\ninstance variables with different implementation details.\n\nSee also:\n\n **PEP 3129** - Class Decorators\n\nClass definitions, like function definitions, may be wrapped by one or\nmore *decorator* expressions. The evaluation rules for the decorator\nexpressions are the same as for functions. The result must be a class\nobject, which is then bound to the class name.\n\n-[ Footnotes ]-\n\n[1] The exception is propagated to the invocation stack only if there\n is no ``finally`` clause that negates the exception.\n\n[2] Currently, control "flows off the end" except in the case of an\n exception or the execution of a ``return``, ``continue``, or\n ``break`` statement.\n\n[3] A string literal appearing as the first statement in the function\n body is transformed into the function\'s ``__doc__`` attribute and\n therefore the function\'s *docstring*.\n\n[4] A string literal appearing as the first statement in the class\n body is transformed into the namespace\'s ``__doc__`` item and\n therefore the class\'s *docstring*.\n', + 'calls': '\nCalls\n*****\n\nA call calls a callable object (e.g., a function) with a possibly\nempty series of arguments:\n\n call ::= primary "(" [argument_list [","] | comprehension] ")"\n argument_list ::= positional_arguments ["," keyword_arguments]\n ["," "*" expression] ["," keyword_arguments]\n ["," "**" expression]\n | keyword_arguments ["," "*" expression]\n ["," keyword_arguments] ["," "**" expression]\n | "*" expression ["," keyword_arguments] ["," "**" expression]\n | "**" expression\n positional_arguments ::= expression ("," expression)*\n keyword_arguments ::= keyword_item ("," keyword_item)*\n keyword_item ::= identifier "=" expression\n\nA trailing comma may be present after the positional and keyword\narguments but does not affect the semantics.\n\nThe primary must evaluate to a callable object (user-defined\nfunctions, built-in functions, methods of built-in objects, class\nobjects, methods of class instances, and all objects having a\n``__call__()`` method are callable). All argument expressions are\nevaluated before the call is attempted. Please refer to section\n*Function definitions* for the syntax of formal parameter lists.\n\nIf keyword arguments are present, they are first converted to\npositional arguments, as follows. First, a list of unfilled slots is\ncreated for the formal parameters. If there are N positional\narguments, they are placed in the first N slots. Next, for each\nkeyword argument, the identifier is used to determine the\ncorresponding slot (if the identifier is the same as the first formal\nparameter name, the first slot is used, and so on). If the slot is\nalready filled, a ``TypeError`` exception is raised. Otherwise, the\nvalue of the argument is placed in the slot, filling it (even if the\nexpression is ``None``, it fills the slot). When all arguments have\nbeen processed, the slots that are still unfilled are filled with the\ncorresponding default value from the function definition. (Default\nvalues are calculated, once, when the function is defined; thus, a\nmutable object such as a list or dictionary used as default value will\nbe shared by all calls that don\'t specify an argument value for the\ncorresponding slot; this should usually be avoided.) If there are any\nunfilled slots for which no default value is specified, a\n``TypeError`` exception is raised. Otherwise, the list of filled\nslots is used as the argument list for the call.\n\n**CPython implementation detail:** An implementation may provide\nbuilt-in functions whose positional parameters do not have names, even\nif they are \'named\' for the purpose of documentation, and which\ntherefore cannot be supplied by keyword. In CPython, this is the case\nfor functions implemented in C that use ``PyArg_ParseTuple()`` to\nparse their arguments.\n\nIf there are more positional arguments than there are formal parameter\nslots, a ``TypeError`` exception is raised, unless a formal parameter\nusing the syntax ``*identifier`` is present; in this case, that formal\nparameter receives a tuple containing the excess positional arguments\n(or an empty tuple if there were no excess positional arguments).\n\nIf any keyword argument does not correspond to a formal parameter\nname, a ``TypeError`` exception is raised, unless a formal parameter\nusing the syntax ``**identifier`` is present; in this case, that\nformal parameter receives a dictionary containing the excess keyword\narguments (using the keywords as keys and the argument values as\ncorresponding values), or a (new) empty dictionary if there were no\nexcess keyword arguments.\n\nIf the syntax ``*expression`` appears in the function call,\n``expression`` must evaluate to a sequence. Elements from this\nsequence are treated as if they were additional positional arguments;\nif there are positional arguments *x1*,..., *xN*, and ``expression``\nevaluates to a sequence *y1*, ..., *yM*, this is equivalent to a call\nwith M+N positional arguments *x1*, ..., *xN*, *y1*, ..., *yM*.\n\nA consequence of this is that although the ``*expression`` syntax may\nappear *after* some keyword arguments, it is processed *before* the\nkeyword arguments (and the ``**expression`` argument, if any -- see\nbelow). So:\n\n >>> def f(a, b):\n ... print(a, b)\n ...\n >>> f(b=1, *(2,))\n 2 1\n >>> f(a=1, *(2,))\n Traceback (most recent call last):\n File "", line 1, in ?\n TypeError: f() got multiple values for keyword argument \'a\'\n >>> f(1, *(2,))\n 1 2\n\nIt is unusual for both keyword arguments and the ``*expression``\nsyntax to be used in the same call, so in practice this confusion does\nnot arise.\n\nIf the syntax ``**expression`` appears in the function call,\n``expression`` must evaluate to a mapping, the contents of which are\ntreated as additional keyword arguments. In the case of a keyword\nappearing in both ``expression`` and as an explicit keyword argument,\na ``TypeError`` exception is raised.\n\nFormal parameters using the syntax ``*identifier`` or ``**identifier``\ncannot be used as positional argument slots or as keyword argument\nnames.\n\nA call always returns some value, possibly ``None``, unless it raises\nan exception. How this value is computed depends on the type of the\ncallable object.\n\nIf it is---\n\na user-defined function:\n The code block for the function is executed, passing it the\n argument list. The first thing the code block will do is bind the\n formal parameters to the arguments; this is described in section\n *Function definitions*. When the code block executes a ``return``\n statement, this specifies the return value of the function call.\n\na built-in function or method:\n The result is up to the interpreter; see *Built-in Functions* for\n the descriptions of built-in functions and methods.\n\na class object:\n A new instance of that class is returned.\n\na class instance method:\n The corresponding user-defined function is called, with an argument\n list that is one longer than the argument list of the call: the\n instance becomes the first argument.\n\na class instance:\n The class must define a ``__call__()`` method; the effect is then\n the same as if that method was called.\n', + 'class': '\nClass definitions\n*****************\n\nA class definition defines a class object (see section *The standard\ntype hierarchy*):\n\n classdef ::= [decorators] "class" classname [inheritance] ":" suite\n inheritance ::= "(" [argument_list [","] | comprehension] ")"\n classname ::= identifier\n\nA class definition is an executable statement. The inheritance list\nusually gives a list of base classes (see *Customizing class creation*\nfor more advanced uses), so each item in the list should evaluate to a\nclass object which allows subclassing. Classes without an inheritance\nlist inherit, by default, from the base class ``object``; hence,\n\n class Foo:\n pass\n\nis equivalent to\n\n class Foo(object):\n pass\n\nThe class\'s suite is then executed in a new execution frame (see\n*Naming and binding*), using a newly created local namespace and the\noriginal global namespace. (Usually, the suite contains mostly\nfunction definitions.) When the class\'s suite finishes execution, its\nexecution frame is discarded but its local namespace is saved. [4] A\nclass object is then created using the inheritance list for the base\nclasses and the saved local namespace for the attribute dictionary.\nThe class name is bound to this class object in the original local\nnamespace.\n\nClass creation can be customized heavily using *metaclasses*.\n\nClasses can also be decorated: just like when decorating functions,\n\n @f1(arg)\n @f2\n class Foo: pass\n\nis equivalent to\n\n class Foo: pass\n Foo = f1(arg)(f2(Foo))\n\nThe evaluation rules for the decorator expressions are the same as for\nfunction decorators. The result must be a class object, which is then\nbound to the class name.\n\n**Programmer\'s note:** Variables defined in the class definition are\nclass attributes; they are shared by instances. Instance attributes\ncan be set in a method with ``self.name = value``. Both class and\ninstance attributes are accessible through the notation\n"``self.name``", and an instance attribute hides a class attribute\nwith the same name when accessed in this way. Class attributes can be\nused as defaults for instance attributes, but using mutable values\nthere can lead to unexpected results. *Descriptors* can be used to\ncreate instance variables with different implementation details.\n\nSee also:\n\n **PEP 3115** - Metaclasses in Python 3 **PEP 3129** - Class\n Decorators\n\n-[ Footnotes ]-\n\n[1] The exception is propagated to the invocation stack only if there\n is no ``finally`` clause that negates the exception.\n\n[2] Currently, control "flows off the end" except in the case of an\n exception or the execution of a ``return``, ``continue``, or\n ``break`` statement.\n\n[3] A string literal appearing as the first statement in the function\n body is transformed into the function\'s ``__doc__`` attribute and\n therefore the function\'s *docstring*.\n\n[4] A string literal appearing as the first statement in the class\n body is transformed into the namespace\'s ``__doc__`` item and\n therefore the class\'s *docstring*.\n', + 'comparisons': '\nComparisons\n***********\n\nUnlike C, all comparison operations in Python have the same priority,\nwhich is lower than that of any arithmetic, shifting or bitwise\noperation. Also unlike C, expressions like ``a < b < c`` have the\ninterpretation that is conventional in mathematics:\n\n comparison ::= or_expr ( comp_operator or_expr )*\n comp_operator ::= "<" | ">" | "==" | ">=" | "<=" | "!="\n | "is" ["not"] | ["not"] "in"\n\nComparisons yield boolean values: ``True`` or ``False``.\n\nComparisons can be chained arbitrarily, e.g., ``x < y <= z`` is\nequivalent to ``x < y and y <= z``, except that ``y`` is evaluated\nonly once (but in both cases ``z`` is not evaluated at all when ``x <\ny`` is found to be false).\n\nFormally, if *a*, *b*, *c*, ..., *y*, *z* are expressions and *op1*,\n*op2*, ..., *opN* are comparison operators, then ``a op1 b op2 c ... y\nopN z`` is equivalent to ``a op1 b and b op2 c and ... y opN z``,\nexcept that each expression is evaluated at most once.\n\nNote that ``a op1 b op2 c`` doesn\'t imply any kind of comparison\nbetween *a* and *c*, so that, e.g., ``x < y > z`` is perfectly legal\n(though perhaps not pretty).\n\nThe operators ``<``, ``>``, ``==``, ``>=``, ``<=``, and ``!=`` compare\nthe values of two objects. The objects need not have the same type.\nIf both are numbers, they are converted to a common type. Otherwise,\nthe ``==`` and ``!=`` operators *always* consider objects of different\ntypes to be unequal, while the ``<``, ``>``, ``>=`` and ``<=``\noperators raise a ``TypeError`` when comparing objects of different\ntypes that do not implement these operators for the given pair of\ntypes. You can control comparison behavior of objects of non-built-in\ntypes by defining rich comparison methods like ``__gt__()``, described\nin section *Basic customization*.\n\nComparison of objects of the same type depends on the type:\n\n* Numbers are compared arithmetically.\n\n* The values ``float(\'NaN\')`` and ``Decimal(\'NaN\')`` are special. The\n are identical to themselves, ``x is x`` but are not equal to\n themselves, ``x != x``. Additionally, comparing any value to a\n not-a-number value will return ``False``. For example, both ``3 <\n float(\'NaN\')`` and ``float(\'NaN\') < 3`` will return ``False``.\n\n* Bytes objects are compared lexicographically using the numeric\n values of their elements.\n\n* Strings are compared lexicographically using the numeric equivalents\n (the result of the built-in function ``ord()``) of their characters.\n [3] String and bytes object can\'t be compared!\n\n* Tuples and lists are compared lexicographically using comparison of\n corresponding elements. This means that to compare equal, each\n element must compare equal and the two sequences must be of the same\n type and have the same length.\n\n If not equal, the sequences are ordered the same as their first\n differing elements. For example, ``[1,2,x] <= [1,2,y]`` has the\n same value as ``x <= y``. If the corresponding element does not\n exist, the shorter sequence is ordered first (for example, ``[1,2] <\n [1,2,3]``).\n\n* Mappings (dictionaries) compare equal if and only if they have the\n same ``(key, value)`` pairs. Order comparisons ``(\'<\', \'<=\', \'>=\',\n \'>\')`` raise ``TypeError``.\n\n* Sets and frozensets define comparison operators to mean subset and\n superset tests. Those relations do not define total orderings (the\n two sets ``{1,2}`` and {2,3} are not equal, nor subsets of one\n another, nor supersets of one another). Accordingly, sets are not\n appropriate arguments for functions which depend on total ordering.\n For example, ``min()``, ``max()``, and ``sorted()`` produce\n undefined results given a list of sets as inputs.\n\n* Most other objects of built-in types compare unequal unless they are\n the same object; the choice whether one object is considered smaller\n or larger than another one is made arbitrarily but consistently\n within one execution of a program.\n\nComparison of objects of the differing types depends on whether either\nof the types provide explicit support for the comparison. Most\nnumeric types can be compared with one another, but comparisons of\n``float`` and ``Decimal`` are not supported to avoid the inevitable\nconfusion arising from representation issues such as ``float(\'1.1\')``\nbeing inexactly represented and therefore not exactly equal to\n``Decimal(\'1.1\')`` which is. When cross-type comparison is not\nsupported, the comparison method returns ``NotImplemented``. This can\ncreate the illusion of non-transitivity between supported cross-type\ncomparisons and unsupported comparisons. For example, ``Decimal(2) ==\n2`` and ``2 == float(2)`` but ``Decimal(2) != float(2)``.\n\nThe operators ``in`` and ``not in`` test for membership. ``x in s``\nevaluates to true if *x* is a member of *s*, and false otherwise. ``x\nnot in s`` returns the negation of ``x in s``. All built-in sequences\nand set types support this as well as dictionary, for which ``in``\ntests whether a the dictionary has a given key. For container types\nsuch as list, tuple, set, frozenset, dict, or collections.deque, the\nexpression ``x in y`` is equivalent to ``any(x is e or x == e for e in\ny)``.\n\nFor the string and bytes types, ``x in y`` is true if and only if *x*\nis a substring of *y*. An equivalent test is ``y.find(x) != -1``.\nEmpty strings are always considered to be a substring of any other\nstring, so ``"" in "abc"`` will return ``True``.\n\nFor user-defined classes which define the ``__contains__()`` method,\n``x in y`` is true if and only if ``y.__contains__(x)`` is true.\n\nFor user-defined classes which do not define ``__contains__()`` but do\ndefine ``__iter__()``, ``x in y`` is true if some value ``z`` with ``x\n== z`` is produced while iterating over ``y``. If an exception is\nraised during the iteration, it is as if ``in`` raised that exception.\n\nLastly, the old-style iteration protocol is tried: if a class defines\n``__getitem__()``, ``x in y`` is true if and only if there is a non-\nnegative integer index *i* such that ``x == y[i]``, and all lower\ninteger indices do not raise ``IndexError`` exception. (If any other\nexception is raised, it is as if ``in`` raised that exception).\n\nThe operator ``not in`` is defined to have the inverse true value of\n``in``.\n\nThe operators ``is`` and ``is not`` test for object identity: ``x is\ny`` is true if and only if *x* and *y* are the same object. ``x is\nnot y`` yields the inverse truth value. [4]\n', + 'compound': '\nCompound statements\n*******************\n\nCompound statements contain (groups of) other statements; they affect\nor control the execution of those other statements in some way. In\ngeneral, compound statements span multiple lines, although in simple\nincarnations a whole compound statement may be contained in one line.\n\nThe ``if``, ``while`` and ``for`` statements implement traditional\ncontrol flow constructs. ``try`` specifies exception handlers and/or\ncleanup code for a group of statements, while the ``with`` statement\nallows the execution of initialization and finalization code around a\nblock of code. Function and class definitions are also syntactically\ncompound statements.\n\nCompound statements consist of one or more \'clauses.\' A clause\nconsists of a header and a \'suite.\' The clause headers of a\nparticular compound statement are all at the same indentation level.\nEach clause header begins with a uniquely identifying keyword and ends\nwith a colon. A suite is a group of statements controlled by a\nclause. A suite can be one or more semicolon-separated simple\nstatements on the same line as the header, following the header\'s\ncolon, or it can be one or more indented statements on subsequent\nlines. Only the latter form of suite can contain nested compound\nstatements; the following is illegal, mostly because it wouldn\'t be\nclear to which ``if`` clause a following ``else`` clause would belong:\n\n if test1: if test2: print(x)\n\nAlso note that the semicolon binds tighter than the colon in this\ncontext, so that in the following example, either all or none of the\n``print()`` calls are executed:\n\n if x < y < z: print(x); print(y); print(z)\n\nSummarizing:\n\n compound_stmt ::= if_stmt\n | while_stmt\n | for_stmt\n | try_stmt\n | with_stmt\n | funcdef\n | classdef\n suite ::= stmt_list NEWLINE | NEWLINE INDENT statement+ DEDENT\n statement ::= stmt_list NEWLINE | compound_stmt\n stmt_list ::= simple_stmt (";" simple_stmt)* [";"]\n\nNote that statements always end in a ``NEWLINE`` possibly followed by\na ``DEDENT``. Also note that optional continuation clauses always\nbegin with a keyword that cannot start a statement, thus there are no\nambiguities (the \'dangling ``else``\' problem is solved in Python by\nrequiring nested ``if`` statements to be indented).\n\nThe formatting of the grammar rules in the following sections places\neach clause on a separate line for clarity.\n\n\nThe ``if`` statement\n====================\n\nThe ``if`` statement is used for conditional execution:\n\n if_stmt ::= "if" expression ":" suite\n ( "elif" expression ":" suite )*\n ["else" ":" suite]\n\nIt selects exactly one of the suites by evaluating the expressions one\nby one until one is found to be true (see section *Boolean operations*\nfor the definition of true and false); then that suite is executed\n(and no other part of the ``if`` statement is executed or evaluated).\nIf all expressions are false, the suite of the ``else`` clause, if\npresent, is executed.\n\n\nThe ``while`` statement\n=======================\n\nThe ``while`` statement is used for repeated execution as long as an\nexpression is true:\n\n while_stmt ::= "while" expression ":" suite\n ["else" ":" suite]\n\nThis repeatedly tests the expression and, if it is true, executes the\nfirst suite; if the expression is false (which may be the first time\nit is tested) the suite of the ``else`` clause, if present, is\nexecuted and the loop terminates.\n\nA ``break`` statement executed in the first suite terminates the loop\nwithout executing the ``else`` clause\'s suite. A ``continue``\nstatement executed in the first suite skips the rest of the suite and\ngoes back to testing the expression.\n\n\nThe ``for`` statement\n=====================\n\nThe ``for`` statement is used to iterate over the elements of a\nsequence (such as a string, tuple or list) or other iterable object:\n\n for_stmt ::= "for" target_list "in" expression_list ":" suite\n ["else" ":" suite]\n\nThe expression list is evaluated once; it should yield an iterable\nobject. An iterator is created for the result of the\n``expression_list``. The suite is then executed once for each item\nprovided by the iterator, in the order of ascending indices. Each\nitem in turn is assigned to the target list using the standard rules\nfor assignments (see *Assignment statements*), and then the suite is\nexecuted. When the items are exhausted (which is immediately when the\nsequence is empty or an iterator raises a ``StopIteration``\nexception), the suite in the ``else`` clause, if present, is executed,\nand the loop terminates.\n\nA ``break`` statement executed in the first suite terminates the loop\nwithout executing the ``else`` clause\'s suite. A ``continue``\nstatement executed in the first suite skips the rest of the suite and\ncontinues with the next item, or with the ``else`` clause if there was\nno next item.\n\nThe suite may assign to the variable(s) in the target list; this does\nnot affect the next item assigned to it.\n\nNames in the target list are not deleted when the loop is finished,\nbut if the sequence is empty, it will not have been assigned to at all\nby the loop. Hint: the built-in function ``range()`` returns an\niterator of integers suitable to emulate the effect of Pascal\'s ``for\ni := a to b do``; e.g., ``list(range(3))`` returns the list ``[0, 1,\n2]``.\n\nNote: There is a subtlety when the sequence is being modified by the loop\n (this can only occur for mutable sequences, i.e. lists). An\n internal counter is used to keep track of which item is used next,\n and this is incremented on each iteration. When this counter has\n reached the length of the sequence the loop terminates. This means\n that if the suite deletes the current (or a previous) item from the\n sequence, the next item will be skipped (since it gets the index of\n the current item which has already been treated). Likewise, if the\n suite inserts an item in the sequence before the current item, the\n current item will be treated again the next time through the loop.\n This can lead to nasty bugs that can be avoided by making a\n temporary copy using a slice of the whole sequence, e.g.,\n\n for x in a[:]:\n if x < 0: a.remove(x)\n\n\nThe ``try`` statement\n=====================\n\nThe ``try`` statement specifies exception handlers and/or cleanup code\nfor a group of statements:\n\n try_stmt ::= try1_stmt | try2_stmt\n try1_stmt ::= "try" ":" suite\n ("except" [expression ["as" target]] ":" suite)+\n ["else" ":" suite]\n ["finally" ":" suite]\n try2_stmt ::= "try" ":" suite\n "finally" ":" suite\n\nThe ``except`` clause(s) specify one or more exception handlers. When\nno exception occurs in the ``try`` clause, no exception handler is\nexecuted. When an exception occurs in the ``try`` suite, a search for\nan exception handler is started. This search inspects the except\nclauses in turn until one is found that matches the exception. An\nexpression-less except clause, if present, must be last; it matches\nany exception. For an except clause with an expression, that\nexpression is evaluated, and the clause matches the exception if the\nresulting object is "compatible" with the exception. An object is\ncompatible with an exception if it is the class or a base class of the\nexception object or a tuple containing an item compatible with the\nexception.\n\nIf no except clause matches the exception, the search for an exception\nhandler continues in the surrounding code and on the invocation stack.\n[1]\n\nIf the evaluation of an expression in the header of an except clause\nraises an exception, the original search for a handler is canceled and\na search starts for the new exception in the surrounding code and on\nthe call stack (it is treated as if the entire ``try`` statement\nraised the exception).\n\nWhen a matching except clause is found, the exception is assigned to\nthe target specified after the ``as`` keyword in that except clause,\nif present, and the except clause\'s suite is executed. All except\nclauses must have an executable block. When the end of this block is\nreached, execution continues normally after the entire try statement.\n(This means that if two nested handlers exist for the same exception,\nand the exception occurs in the try clause of the inner handler, the\nouter handler will not handle the exception.)\n\nWhen an exception has been assigned using ``as target``, it is cleared\nat the end of the except clause. This is as if\n\n except E as N:\n foo\n\nwas translated to\n\n except E as N:\n try:\n foo\n finally:\n del N\n\nThis means the exception must be assigned to a different name to be\nable to refer to it after the except clause. Exceptions are cleared\nbecause with the traceback attached to them, they form a reference\ncycle with the stack frame, keeping all locals in that frame alive\nuntil the next garbage collection occurs.\n\nBefore an except clause\'s suite is executed, details about the\nexception are stored in the ``sys`` module and can be access via\n``sys.exc_info()``. ``sys.exc_info()`` returns a 3-tuple consisting of\nthe exception class, the exception instance and a traceback object\n(see section *The standard type hierarchy*) identifying the point in\nthe program where the exception occurred. ``sys.exc_info()`` values\nare restored to their previous values (before the call) when returning\nfrom a function that handled an exception.\n\nThe optional ``else`` clause is executed if and when control flows off\nthe end of the ``try`` clause. [2] Exceptions in the ``else`` clause\nare not handled by the preceding ``except`` clauses.\n\nIf ``finally`` is present, it specifies a \'cleanup\' handler. The\n``try`` clause is executed, including any ``except`` and ``else``\nclauses. If an exception occurs in any of the clauses and is not\nhandled, the exception is temporarily saved. The ``finally`` clause is\nexecuted. If there is a saved exception, it is re-raised at the end\nof the ``finally`` clause. If the ``finally`` clause raises another\nexception or executes a ``return`` or ``break`` statement, the saved\nexception is lost. The exception information is not available to the\nprogram during execution of the ``finally`` clause.\n\nWhen a ``return``, ``break`` or ``continue`` statement is executed in\nthe ``try`` suite of a ``try``...``finally`` statement, the\n``finally`` clause is also executed \'on the way out.\' A ``continue``\nstatement is illegal in the ``finally`` clause. (The reason is a\nproblem with the current implementation --- this restriction may be\nlifted in the future).\n\nAdditional information on exceptions can be found in section\n*Exceptions*, and information on using the ``raise`` statement to\ngenerate exceptions may be found in section *The raise statement*.\n\n\nThe ``with`` statement\n======================\n\nThe ``with`` statement is used to wrap the execution of a block with\nmethods defined by a context manager (see section *With Statement\nContext Managers*). This allows common\n``try``...``except``...``finally`` usage patterns to be encapsulated\nfor convenient reuse.\n\n with_stmt ::= "with" with_item ("," with_item)* ":" suite\n with_item ::= expression ["as" target]\n\nThe execution of the ``with`` statement with one "item" proceeds as\nfollows:\n\n1. The context expression (the expression given in the **with_item**)\n is evaluated to obtain a context manager.\n\n2. The context manager\'s ``__enter__()`` method is invoked.\n\n3. If a target was included in the ``with`` statement, the return\n value from ``__enter__()`` is assigned to it.\n\n Note: The ``with`` statement guarantees that if the ``__enter__()``\n method returns without an error, then ``__exit__()`` will always\n be called. Thus, if an error occurs during the assignment to the\n target list, it will be treated the same as an error occurring\n within the suite would be. See step 5 below.\n\n4. The suite is executed.\n\n5. The context manager\'s ``__exit__()`` method is invoked. If an\n exception caused the suite to be exited, its type, value, and\n traceback are passed as arguments to ``__exit__()``. Otherwise,\n three ``None`` arguments are supplied.\n\n If the suite was exited due to an exception, and the return value\n from the ``__exit__()`` method was false, the exception is\n reraised. If the return value was true, the exception is\n suppressed, and execution continues with the statement following\n the ``with`` statement.\n\n If the suite was exited for any reason other than an exception, the\n return value from ``__exit__()`` is ignored, and execution proceeds\n at the normal location for the kind of exit that was taken.\n\nWith more than one item, the context managers are processed as if\nmultiple ``with`` statements were nested:\n\n with A() as a, B() as b:\n suite\n\nis equivalent to\n\n with A() as a:\n with B() as b:\n suite\n\nChanged in version 3.1: Support for multiple context expressions.\n\nSee also:\n\n **PEP 0343** - The "with" statement\n The specification, background, and examples for the Python\n ``with`` statement.\n\n\nFunction definitions\n====================\n\nA function definition defines a user-defined function object (see\nsection *The standard type hierarchy*):\n\n funcdef ::= [decorators] "def" funcname "(" [parameter_list] ")" ["->" expression] ":" suite\n decorators ::= decorator+\n decorator ::= "@" dotted_name ["(" [argument_list [","]] ")"] NEWLINE\n dotted_name ::= identifier ("." identifier)*\n parameter_list ::= (defparameter ",")*\n ( "*" [parameter] ("," defparameter)*\n [, "**" parameter]\n | "**" parameter\n | defparameter [","] )\n parameter ::= identifier [":" expression]\n defparameter ::= parameter ["=" expression]\n funcname ::= identifier\n\nA function definition is an executable statement. Its execution binds\nthe function name in the current local namespace to a function object\n(a wrapper around the executable code for the function). This\nfunction object contains a reference to the current global namespace\nas the global namespace to be used when the function is called.\n\nThe function definition does not execute the function body; this gets\nexecuted only when the function is called. [3]\n\nA function definition may be wrapped by one or more *decorator*\nexpressions. Decorator expressions are evaluated when the function is\ndefined, in the scope that contains the function definition. The\nresult must be a callable, which is invoked with the function object\nas the only argument. The returned value is bound to the function name\ninstead of the function object. Multiple decorators are applied in\nnested fashion. For example, the following code\n\n @f1(arg)\n @f2\n def func(): pass\n\nis equivalent to\n\n def func(): pass\n func = f1(arg)(f2(func))\n\nWhen one or more parameters have the form *parameter* ``=``\n*expression*, the function is said to have "default parameter values."\nFor a parameter with a default value, the corresponding argument may\nbe omitted from a call, in which case the parameter\'s default value is\nsubstituted. If a parameter has a default value, all following\nparameters up until the "``*``" must also have a default value ---\nthis is a syntactic restriction that is not expressed by the grammar.\n\n**Default parameter values are evaluated when the function definition\nis executed.** This means that the expression is evaluated once, when\nthe function is defined, and that that same "pre-computed" value is\nused for each call. This is especially important to understand when a\ndefault parameter is a mutable object, such as a list or a dictionary:\nif the function modifies the object (e.g. by appending an item to a\nlist), the default value is in effect modified. This is generally not\nwhat was intended. A way around this is to use ``None`` as the\ndefault, and explicitly test for it in the body of the function, e.g.:\n\n def whats_on_the_telly(penguin=None):\n if penguin is None:\n penguin = []\n penguin.append("property of the zoo")\n return penguin\n\nFunction call semantics are described in more detail in section\n*Calls*. A function call always assigns values to all parameters\nmentioned in the parameter list, either from position arguments, from\nkeyword arguments, or from default values. If the form\n"``*identifier``" is present, it is initialized to a tuple receiving\nany excess positional parameters, defaulting to the empty tuple. If\nthe form "``**identifier``" is present, it is initialized to a new\ndictionary receiving any excess keyword arguments, defaulting to a new\nempty dictionary. Parameters after "``*``" or "``*identifier``" are\nkeyword-only parameters and may only be passed used keyword arguments.\n\nParameters may have annotations of the form "``: expression``"\nfollowing the parameter name. Any parameter may have an annotation\neven those of the form ``*identifier`` or ``**identifier``. Functions\nmay have "return" annotation of the form "``-> expression``" after the\nparameter list. These annotations can be any valid Python expression\nand are evaluated when the function definition is executed.\nAnnotations may be evaluated in a different order than they appear in\nthe source code. The presence of annotations does not change the\nsemantics of a function. The annotation values are available as\nvalues of a dictionary keyed by the parameters\' names in the\n``__annotations__`` attribute of the function object.\n\nIt is also possible to create anonymous functions (functions not bound\nto a name), for immediate use in expressions. This uses lambda forms,\ndescribed in section *Lambdas*. Note that the lambda form is merely a\nshorthand for a simplified function definition; a function defined in\na "``def``" statement can be passed around or assigned to another name\njust like a function defined by a lambda form. The "``def``" form is\nactually more powerful since it allows the execution of multiple\nstatements and annotations.\n\n**Programmer\'s note:** Functions are first-class objects. A "``def``"\nform executed inside a function definition defines a local function\nthat can be returned or passed around. Free variables used in the\nnested function can access the local variables of the function\ncontaining the def. See section *Naming and binding* for details.\n\n\nClass definitions\n=================\n\nA class definition defines a class object (see section *The standard\ntype hierarchy*):\n\n classdef ::= [decorators] "class" classname [inheritance] ":" suite\n inheritance ::= "(" [argument_list [","] | comprehension] ")"\n classname ::= identifier\n\nA class definition is an executable statement. The inheritance list\nusually gives a list of base classes (see *Customizing class creation*\nfor more advanced uses), so each item in the list should evaluate to a\nclass object which allows subclassing. Classes without an inheritance\nlist inherit, by default, from the base class ``object``; hence,\n\n class Foo:\n pass\n\nis equivalent to\n\n class Foo(object):\n pass\n\nThe class\'s suite is then executed in a new execution frame (see\n*Naming and binding*), using a newly created local namespace and the\noriginal global namespace. (Usually, the suite contains mostly\nfunction definitions.) When the class\'s suite finishes execution, its\nexecution frame is discarded but its local namespace is saved. [4] A\nclass object is then created using the inheritance list for the base\nclasses and the saved local namespace for the attribute dictionary.\nThe class name is bound to this class object in the original local\nnamespace.\n\nClass creation can be customized heavily using *metaclasses*.\n\nClasses can also be decorated: just like when decorating functions,\n\n @f1(arg)\n @f2\n class Foo: pass\n\nis equivalent to\n\n class Foo: pass\n Foo = f1(arg)(f2(Foo))\n\nThe evaluation rules for the decorator expressions are the same as for\nfunction decorators. The result must be a class object, which is then\nbound to the class name.\n\n**Programmer\'s note:** Variables defined in the class definition are\nclass attributes; they are shared by instances. Instance attributes\ncan be set in a method with ``self.name = value``. Both class and\ninstance attributes are accessible through the notation\n"``self.name``", and an instance attribute hides a class attribute\nwith the same name when accessed in this way. Class attributes can be\nused as defaults for instance attributes, but using mutable values\nthere can lead to unexpected results. *Descriptors* can be used to\ncreate instance variables with different implementation details.\n\nSee also:\n\n **PEP 3115** - Metaclasses in Python 3 **PEP 3129** - Class\n Decorators\n\n-[ Footnotes ]-\n\n[1] The exception is propagated to the invocation stack only if there\n is no ``finally`` clause that negates the exception.\n\n[2] Currently, control "flows off the end" except in the case of an\n exception or the execution of a ``return``, ``continue``, or\n ``break`` statement.\n\n[3] A string literal appearing as the first statement in the function\n body is transformed into the function\'s ``__doc__`` attribute and\n therefore the function\'s *docstring*.\n\n[4] A string literal appearing as the first statement in the class\n body is transformed into the namespace\'s ``__doc__`` item and\n therefore the class\'s *docstring*.\n', 'context-managers': '\nWith Statement Context Managers\n*******************************\n\nA *context manager* is an object that defines the runtime context to\nbe established when executing a ``with`` statement. The context\nmanager handles the entry into, and the exit from, the desired runtime\ncontext for the execution of the block of code. Context managers are\nnormally invoked using the ``with`` statement (described in section\n*The with statement*), but can also be used by directly invoking their\nmethods.\n\nTypical uses of context managers include saving and restoring various\nkinds of global state, locking and unlocking resources, closing opened\nfiles, etc.\n\nFor more information on context managers, see *Context Manager Types*.\n\nobject.__enter__(self)\n\n Enter the runtime context related to this object. The ``with``\n statement will bind this method\'s return value to the target(s)\n specified in the ``as`` clause of the statement, if any.\n\nobject.__exit__(self, exc_type, exc_value, traceback)\n\n Exit the runtime context related to this object. The parameters\n describe the exception that caused the context to be exited. If the\n context was exited without an exception, all three arguments will\n be ``None``.\n\n If an exception is supplied, and the method wishes to suppress the\n exception (i.e., prevent it from being propagated), it should\n return a true value. Otherwise, the exception will be processed\n normally upon exit from this method.\n\n Note that ``__exit__()`` methods should not reraise the passed-in\n exception; this is the caller\'s responsibility.\n\nSee also:\n\n **PEP 0343** - The "with" statement\n The specification, background, and examples for the Python\n ``with`` statement.\n', 'continue': '\nThe ``continue`` statement\n**************************\n\n continue_stmt ::= "continue"\n\n``continue`` may only occur syntactically nested in a ``for`` or\n``while`` loop, but not nested in a function or class definition or\n``finally`` clause within that loop. It continues with the next cycle\nof the nearest enclosing loop.\n\nWhen ``continue`` passes control out of a ``try`` statement with a\n``finally`` clause, that ``finally`` clause is executed before really\nstarting the next loop cycle.\n', 'conversions': '\nArithmetic conversions\n**********************\n\nWhen a description of an arithmetic operator below uses the phrase\n"the numeric arguments are converted to a common type," this means\nthat the operator implementation for built-in types works that way:\n\n* If either argument is a complex number, the other is converted to\n complex;\n\n* otherwise, if either argument is a floating point number, the other\n is converted to floating point;\n\n* otherwise, both must be integers and no conversion is necessary.\n\nSome additional rules apply for certain operators (e.g., a string left\nargument to the \'%\' operator). Extensions must define their own\nconversion behavior.\n', - 'customization': '\nBasic customization\n*******************\n\nobject.__new__(cls[, ...])\n\n Called to create a new instance of class *cls*. ``__new__()`` is a\n static method (special-cased so you need not declare it as such)\n that takes the class of which an instance was requested as its\n first argument. The remaining arguments are those passed to the\n object constructor expression (the call to the class). The return\n value of ``__new__()`` should be the new object instance (usually\n an instance of *cls*).\n\n Typical implementations create a new instance of the class by\n invoking the superclass\'s ``__new__()`` method using\n ``super(currentclass, cls).__new__(cls[, ...])`` with appropriate\n arguments and then modifying the newly-created instance as\n necessary before returning it.\n\n If ``__new__()`` returns an instance of *cls*, then the new\n instance\'s ``__init__()`` method will be invoked like\n ``__init__(self[, ...])``, where *self* is the new instance and the\n remaining arguments are the same as were passed to ``__new__()``.\n\n If ``__new__()`` does not return an instance of *cls*, then the new\n instance\'s ``__init__()`` method will not be invoked.\n\n ``__new__()`` is intended mainly to allow subclasses of immutable\n types (like int, str, or tuple) to customize instance creation. It\n is also commonly overridden in custom metaclasses in order to\n customize class creation.\n\nobject.__init__(self[, ...])\n\n Called when the instance is created. The arguments are those\n passed to the class constructor expression. If a base class has an\n ``__init__()`` method, the derived class\'s ``__init__()`` method,\n if any, must explicitly call it to ensure proper initialization of\n the base class part of the instance; for example:\n ``BaseClass.__init__(self, [args...])``. As a special constraint\n on constructors, no value may be returned; doing so will cause a\n ``TypeError`` to be raised at runtime.\n\nobject.__del__(self)\n\n Called when the instance is about to be destroyed. This is also\n called a destructor. If a base class has a ``__del__()`` method,\n the derived class\'s ``__del__()`` method, if any, must explicitly\n call it to ensure proper deletion of the base class part of the\n instance. Note that it is possible (though not recommended!) for\n the ``__del__()`` method to postpone destruction of the instance by\n creating a new reference to it. It may then be called at a later\n time when this new reference is deleted. It is not guaranteed that\n ``__del__()`` methods are called for objects that still exist when\n the interpreter exits.\n\n Note: ``del x`` doesn\'t directly call ``x.__del__()`` --- the former\n decrements the reference count for ``x`` by one, and the latter\n is only called when ``x``\'s reference count reaches zero. Some\n common situations that may prevent the reference count of an\n object from going to zero include: circular references between\n objects (e.g., a doubly-linked list or a tree data structure with\n parent and child pointers); a reference to the object on the\n stack frame of a function that caught an exception (the traceback\n stored in ``sys.exc_info()[2]`` keeps the stack frame alive); or\n a reference to the object on the stack frame that raised an\n unhandled exception in interactive mode (the traceback stored in\n ``sys.last_traceback`` keeps the stack frame alive). The first\n situation can only be remedied by explicitly breaking the cycles;\n the latter two situations can be resolved by storing ``None`` in\n ``sys.last_traceback``. Circular references which are garbage are\n detected when the option cycle detector is enabled (it\'s on by\n default), but can only be cleaned up if there are no Python-\n level ``__del__()`` methods involved. Refer to the documentation\n for the ``gc`` module for more information about how\n ``__del__()`` methods are handled by the cycle detector,\n particularly the description of the ``garbage`` value.\n\n Warning: Due to the precarious circumstances under which ``__del__()``\n methods are invoked, exceptions that occur during their execution\n are ignored, and a warning is printed to ``sys.stderr`` instead.\n Also, when ``__del__()`` is invoked in response to a module being\n deleted (e.g., when execution of the program is done), other\n globals referenced by the ``__del__()`` method may already have\n been deleted or in the process of being torn down (e.g. the\n import machinery shutting down). For this reason, ``__del__()``\n methods should do the absolute minimum needed to maintain\n external invariants. Starting with version 1.5, Python\n guarantees that globals whose name begins with a single\n underscore are deleted from their module before other globals are\n deleted; if no other references to such globals exist, this may\n help in assuring that imported modules are still available at the\n time when the ``__del__()`` method is called.\n\nobject.__repr__(self)\n\n Called by the ``repr()`` built-in function to compute the\n "official" string representation of an object. If at all possible,\n this should look like a valid Python expression that could be used\n to recreate an object with the same value (given an appropriate\n environment). If this is not possible, a string of the form\n ``<...some useful description...>`` should be returned. The return\n value must be a string object. If a class defines ``__repr__()``\n but not ``__str__()``, then ``__repr__()`` is also used when an\n "informal" string representation of instances of that class is\n required.\n\n This is typically used for debugging, so it is important that the\n representation is information-rich and unambiguous.\n\nobject.__str__(self)\n\n Called by the ``str()`` built-in function and by the ``print()``\n function to compute the "informal" string representation of an\n object. This differs from ``__repr__()`` in that it does not have\n to be a valid Python expression: a more convenient or concise\n representation may be used instead. The return value must be a\n string object.\n\nobject.__format__(self, format_spec)\n\n Called by the ``format()`` built-in function (and by extension, the\n ``format()`` method of class ``str``) to produce a "formatted"\n string representation of an object. The ``format_spec`` argument is\n a string that contains a description of the formatting options\n desired. The interpretation of the ``format_spec`` argument is up\n to the type implementing ``__format__()``, however most classes\n will either delegate formatting to one of the built-in types, or\n use a similar formatting option syntax.\n\n See *Format Specification Mini-Language* for a description of the\n standard formatting syntax.\n\n The return value must be a string object.\n\nobject.__lt__(self, other)\nobject.__le__(self, other)\nobject.__eq__(self, other)\nobject.__ne__(self, other)\nobject.__gt__(self, other)\nobject.__ge__(self, other)\n\n These are the so-called "rich comparison" methods. The\n correspondence between operator symbols and method names is as\n follows: ``xy`` calls ``x.__gt__(y)``, and ``x>=y`` calls\n ``x.__ge__(y)``.\n\n A rich comparison method may return the singleton\n ``NotImplemented`` if it does not implement the operation for a\n given pair of arguments. By convention, ``False`` and ``True`` are\n returned for a successful comparison. However, these methods can\n return any value, so if the comparison operator is used in a\n Boolean context (e.g., in the condition of an ``if`` statement),\n Python will call ``bool()`` on the value to determine if the result\n is true or false.\n\n There are no implied relationships among the comparison operators.\n The truth of ``x==y`` does not imply that ``x!=y`` is false.\n Accordingly, when defining ``__eq__()``, one should also define\n ``__ne__()`` so that the operators will behave as expected. See\n the paragraph on ``__hash__()`` for some important notes on\n creating *hashable* objects which support custom comparison\n operations and are usable as dictionary keys.\n\n There are no swapped-argument versions of these methods (to be used\n when the left argument does not support the operation but the right\n argument does); rather, ``__lt__()`` and ``__gt__()`` are each\n other\'s reflection, ``__le__()`` and ``__ge__()`` are each other\'s\n reflection, and ``__eq__()`` and ``__ne__()`` are their own\n reflection.\n\n Arguments to rich comparison methods are never coerced.\n\n To automatically generate ordering operations from a single root\n operation, see the Total Ordering recipe in the ASPN cookbook.\n\nobject.__hash__(self)\n\n Called by built-in function ``hash()`` and for operations on\n members of hashed collections including ``set``, ``frozenset``, and\n ``dict``. ``__hash__()`` should return an integer. The only\n required property is that objects which compare equal have the same\n hash value; it is advised to somehow mix together (e.g. using\n exclusive or) the hash values for the components of the object that\n also play a part in comparison of objects.\n\n If a class does not define an ``__eq__()`` method it should not\n define a ``__hash__()`` operation either; if it defines\n ``__eq__()`` but not ``__hash__()``, its instances will not be\n usable as items in hashable collections. If a class defines\n mutable objects and implements an ``__eq__()`` method, it should\n not implement ``__hash__()``, since the implementation of hashable\n collections requires that a key\'s hash value is immutable (if the\n object\'s hash value changes, it will be in the wrong hash bucket).\n\n User-defined classes have ``__eq__()`` and ``__hash__()`` methods\n by default; with them, all objects compare unequal (except with\n themselves) and ``x.__hash__()`` returns ``id(x)``.\n\n Classes which inherit a ``__hash__()`` method from a parent class\n but change the meaning of ``__eq__()`` such that the hash value\n returned is no longer appropriate (e.g. by switching to a value-\n based concept of equality instead of the default identity based\n equality) can explicitly flag themselves as being unhashable by\n setting ``__hash__ = None`` in the class definition. Doing so means\n that not only will instances of the class raise an appropriate\n ``TypeError`` when a program attempts to retrieve their hash value,\n but they will also be correctly identified as unhashable when\n checking ``isinstance(obj, collections.Hashable)`` (unlike classes\n which define their own ``__hash__()`` to explicitly raise\n ``TypeError``).\n\n If a class that overrides ``__eq__()`` needs to retain the\n implementation of ``__hash__()`` from a parent class, the\n interpreter must be told this explicitly by setting ``__hash__ =\n .__hash__``. Otherwise the inheritance of\n ``__hash__()`` will be blocked, just as if ``__hash__`` had been\n explicitly set to ``None``.\n\nobject.__bool__(self)\n\n Called to implement truth value testing and the built-in operation\n ``bool()``; should return ``False`` or ``True``, or their integer\n equivalents ``0`` or ``1``. When this method is not defined,\n ``__len__()`` is called, if it is defined, and the object is\n considered true if its result is nonzero. If a class defines\n neither ``__len__()`` nor ``__bool__()``, all its instances are\n considered true.\n', - 'debugger': '\n``pdb`` --- The Python Debugger\n*******************************\n\nThe module ``pdb`` defines an interactive source code debugger for\nPython programs. It supports setting (conditional) breakpoints and\nsingle stepping at the source line level, inspection of stack frames,\nsource code listing, and evaluation of arbitrary Python code in the\ncontext of any stack frame. It also supports post-mortem debugging\nand can be called under program control.\n\nThe debugger is extensible --- it is actually defined as the class\n``Pdb``. This is currently undocumented but easily understood by\nreading the source. The extension interface uses the modules ``bdb``\n(undocumented) and ``cmd``.\n\nThe debugger\'s prompt is ``(Pdb)``. Typical usage to run a program\nunder control of the debugger is:\n\n >>> import pdb\n >>> import mymodule\n >>> pdb.run(\'mymodule.test()\')\n > (0)?()\n (Pdb) continue\n > (1)?()\n (Pdb) continue\n NameError: \'spam\'\n > (1)?()\n (Pdb)\n\n``pdb.py`` can also be invoked as a script to debug other scripts.\nFor example:\n\n python -m pdb myscript.py\n\nWhen invoked as a script, pdb will automatically enter post-mortem\ndebugging if the program being debugged exits abnormally. After post-\nmortem debugging (or after normal exit of the program), pdb will\nrestart the program. Automatic restarting preserves pdb\'s state (such\nas breakpoints) and in most cases is more useful than quitting the\ndebugger upon program\'s exit.\n\nThe typical usage to break into the debugger from a running program is\nto insert\n\n import pdb; pdb.set_trace()\n\nat the location you want to break into the debugger. You can then\nstep through the code following this statement, and continue running\nwithout debugger using the ``c`` command.\n\nThe typical usage to inspect a crashed program is:\n\n >>> import pdb\n >>> import mymodule\n >>> mymodule.test()\n Traceback (most recent call last):\n File "", line 1, in ?\n File "./mymodule.py", line 4, in test\n test2()\n File "./mymodule.py", line 3, in test2\n print(spam)\n NameError: spam\n >>> pdb.pm()\n > ./mymodule.py(3)test2()\n -> print(spam)\n (Pdb)\n\nThe module defines the following functions; each enters the debugger\nin a slightly different way:\n\npdb.run(statement[, globals[, locals]])\n\n Execute the *statement* (given as a string) under debugger control.\n The debugger prompt appears before any code is executed; you can\n set breakpoints and type ``continue``, or you can step through the\n statement using ``step`` or ``next`` (all these commands are\n explained below). The optional *globals* and *locals* arguments\n specify the environment in which the code is executed; by default\n the dictionary of the module ``__main__`` is used. (See the\n explanation of the built-in ``exec()`` or ``eval()`` functions.)\n\npdb.runeval(expression[, globals[, locals]])\n\n Evaluate the *expression* (given as a string) under debugger\n control. When ``runeval()`` returns, it returns the value of the\n expression. Otherwise this function is similar to ``run()``.\n\npdb.runcall(function[, argument, ...])\n\n Call the *function* (a function or method object, not a string)\n with the given arguments. When ``runcall()`` returns, it returns\n whatever the function call returned. The debugger prompt appears\n as soon as the function is entered.\n\npdb.set_trace()\n\n Enter the debugger at the calling stack frame. This is useful to\n hard-code a breakpoint at a given point in a program, even if the\n code is not otherwise being debugged (e.g. when an assertion\n fails).\n\npdb.post_mortem([traceback])\n\n Enter post-mortem debugging of the given *traceback* object. If no\n *traceback* is given, it uses the one of the exception that is\n currently being handled (an exception must be being handled if the\n default is to be used).\n\npdb.pm()\n\n Enter post-mortem debugging of the traceback found in\n ``sys.last_traceback``.\n\nThe ``run_*`` functions and ``set_trace()`` are aliases for\ninstantiating the ``Pdb`` class and calling the method of the same\nname. If you want to access further features, you have to do this\nyourself:\n\nclass class pdb.Pdb(completekey=\'tab\', stdin=None, stdout=None, skip=None)\n\n ``Pdb`` is the debugger class.\n\n The *completekey*, *stdin* and *stdout* arguments are passed to the\n underlying ``cmd.Cmd`` class; see the description there.\n\n The *skip* argument, if given, must be an iterable of glob-style\n module name patterns. The debugger will not step into frames that\n originate in a module that matches one of these patterns. [1]\n\n Example call to enable tracing with *skip*:\n\n import pdb; pdb.Pdb(skip=[\'django.*\']).set_trace()\n\n New in version 3.1: The *skip* argument.\n\n run(statement[, globals[, locals]])\n runeval(expression[, globals[, locals]])\n runcall(function[, argument, ...])\n set_trace()\n\n See the documentation for the functions explained above.\n', + 'customization': '\nBasic customization\n*******************\n\nobject.__new__(cls[, ...])\n\n Called to create a new instance of class *cls*. ``__new__()`` is a\n static method (special-cased so you need not declare it as such)\n that takes the class of which an instance was requested as its\n first argument. The remaining arguments are those passed to the\n object constructor expression (the call to the class). The return\n value of ``__new__()`` should be the new object instance (usually\n an instance of *cls*).\n\n Typical implementations create a new instance of the class by\n invoking the superclass\'s ``__new__()`` method using\n ``super(currentclass, cls).__new__(cls[, ...])`` with appropriate\n arguments and then modifying the newly-created instance as\n necessary before returning it.\n\n If ``__new__()`` returns an instance of *cls*, then the new\n instance\'s ``__init__()`` method will be invoked like\n ``__init__(self[, ...])``, where *self* is the new instance and the\n remaining arguments are the same as were passed to ``__new__()``.\n\n If ``__new__()`` does not return an instance of *cls*, then the new\n instance\'s ``__init__()`` method will not be invoked.\n\n ``__new__()`` is intended mainly to allow subclasses of immutable\n types (like int, str, or tuple) to customize instance creation. It\n is also commonly overridden in custom metaclasses in order to\n customize class creation.\n\nobject.__init__(self[, ...])\n\n Called when the instance is created. The arguments are those\n passed to the class constructor expression. If a base class has an\n ``__init__()`` method, the derived class\'s ``__init__()`` method,\n if any, must explicitly call it to ensure proper initialization of\n the base class part of the instance; for example:\n ``BaseClass.__init__(self, [args...])``. As a special constraint\n on constructors, no value may be returned; doing so will cause a\n ``TypeError`` to be raised at runtime.\n\nobject.__del__(self)\n\n Called when the instance is about to be destroyed. This is also\n called a destructor. If a base class has a ``__del__()`` method,\n the derived class\'s ``__del__()`` method, if any, must explicitly\n call it to ensure proper deletion of the base class part of the\n instance. Note that it is possible (though not recommended!) for\n the ``__del__()`` method to postpone destruction of the instance by\n creating a new reference to it. It may then be called at a later\n time when this new reference is deleted. It is not guaranteed that\n ``__del__()`` methods are called for objects that still exist when\n the interpreter exits.\n\n Note: ``del x`` doesn\'t directly call ``x.__del__()`` --- the former\n decrements the reference count for ``x`` by one, and the latter\n is only called when ``x``\'s reference count reaches zero. Some\n common situations that may prevent the reference count of an\n object from going to zero include: circular references between\n objects (e.g., a doubly-linked list or a tree data structure with\n parent and child pointers); a reference to the object on the\n stack frame of a function that caught an exception (the traceback\n stored in ``sys.exc_info()[2]`` keeps the stack frame alive); or\n a reference to the object on the stack frame that raised an\n unhandled exception in interactive mode (the traceback stored in\n ``sys.last_traceback`` keeps the stack frame alive). The first\n situation can only be remedied by explicitly breaking the cycles;\n the latter two situations can be resolved by storing ``None`` in\n ``sys.last_traceback``. Circular references which are garbage are\n detected when the option cycle detector is enabled (it\'s on by\n default), but can only be cleaned up if there are no Python-\n level ``__del__()`` methods involved. Refer to the documentation\n for the ``gc`` module for more information about how\n ``__del__()`` methods are handled by the cycle detector,\n particularly the description of the ``garbage`` value.\n\n Warning: Due to the precarious circumstances under which ``__del__()``\n methods are invoked, exceptions that occur during their execution\n are ignored, and a warning is printed to ``sys.stderr`` instead.\n Also, when ``__del__()`` is invoked in response to a module being\n deleted (e.g., when execution of the program is done), other\n globals referenced by the ``__del__()`` method may already have\n been deleted or in the process of being torn down (e.g. the\n import machinery shutting down). For this reason, ``__del__()``\n methods should do the absolute minimum needed to maintain\n external invariants. Starting with version 1.5, Python\n guarantees that globals whose name begins with a single\n underscore are deleted from their module before other globals are\n deleted; if no other references to such globals exist, this may\n help in assuring that imported modules are still available at the\n time when the ``__del__()`` method is called.\n\nobject.__repr__(self)\n\n Called by the ``repr()`` built-in function to compute the\n "official" string representation of an object. If at all possible,\n this should look like a valid Python expression that could be used\n to recreate an object with the same value (given an appropriate\n environment). If this is not possible, a string of the form\n ``<...some useful description...>`` should be returned. The return\n value must be a string object. If a class defines ``__repr__()``\n but not ``__str__()``, then ``__repr__()`` is also used when an\n "informal" string representation of instances of that class is\n required.\n\n This is typically used for debugging, so it is important that the\n representation is information-rich and unambiguous.\n\nobject.__str__(self)\n\n Called by the ``str()`` built-in function and by the ``print()``\n function to compute the "informal" string representation of an\n object. This differs from ``__repr__()`` in that it does not have\n to be a valid Python expression: a more convenient or concise\n representation may be used instead. The return value must be a\n string object.\n\nobject.__format__(self, format_spec)\n\n Called by the ``format()`` built-in function (and by extension, the\n ``format()`` method of class ``str``) to produce a "formatted"\n string representation of an object. The ``format_spec`` argument is\n a string that contains a description of the formatting options\n desired. The interpretation of the ``format_spec`` argument is up\n to the type implementing ``__format__()``, however most classes\n will either delegate formatting to one of the built-in types, or\n use a similar formatting option syntax.\n\n See *Format Specification Mini-Language* for a description of the\n standard formatting syntax.\n\n The return value must be a string object.\n\nobject.__lt__(self, other)\nobject.__le__(self, other)\nobject.__eq__(self, other)\nobject.__ne__(self, other)\nobject.__gt__(self, other)\nobject.__ge__(self, other)\n\n These are the so-called "rich comparison" methods. The\n correspondence between operator symbols and method names is as\n follows: ``xy`` calls ``x.__gt__(y)``, and ``x>=y`` calls\n ``x.__ge__(y)``.\n\n A rich comparison method may return the singleton\n ``NotImplemented`` if it does not implement the operation for a\n given pair of arguments. By convention, ``False`` and ``True`` are\n returned for a successful comparison. However, these methods can\n return any value, so if the comparison operator is used in a\n Boolean context (e.g., in the condition of an ``if`` statement),\n Python will call ``bool()`` on the value to determine if the result\n is true or false.\n\n There are no implied relationships among the comparison operators.\n The truth of ``x==y`` does not imply that ``x!=y`` is false.\n Accordingly, when defining ``__eq__()``, one should also define\n ``__ne__()`` so that the operators will behave as expected. See\n the paragraph on ``__hash__()`` for some important notes on\n creating *hashable* objects which support custom comparison\n operations and are usable as dictionary keys.\n\n There are no swapped-argument versions of these methods (to be used\n when the left argument does not support the operation but the right\n argument does); rather, ``__lt__()`` and ``__gt__()`` are each\n other\'s reflection, ``__le__()`` and ``__ge__()`` are each other\'s\n reflection, and ``__eq__()`` and ``__ne__()`` are their own\n reflection.\n\n Arguments to rich comparison methods are never coerced.\n\n To automatically generate ordering operations from a single root\n operation, see the Total Ordering recipe in the ASPN cookbook.\n\nobject.__hash__(self)\n\n Called by built-in function ``hash()`` and for operations on\n members of hashed collections including ``set``, ``frozenset``, and\n ``dict``. ``__hash__()`` should return an integer. The only\n required property is that objects which compare equal have the same\n hash value; it is advised to somehow mix together (e.g. using\n exclusive or) the hash values for the components of the object that\n also play a part in comparison of objects.\n\n If a class does not define an ``__eq__()`` method it should not\n define a ``__hash__()`` operation either; if it defines\n ``__eq__()`` but not ``__hash__()``, its instances will not be\n usable as items in hashable collections. If a class defines\n mutable objects and implements an ``__eq__()`` method, it should\n not implement ``__hash__()``, since the implementation of hashable\n collections requires that a key\'s hash value is immutable (if the\n object\'s hash value changes, it will be in the wrong hash bucket).\n\n User-defined classes have ``__eq__()`` and ``__hash__()`` methods\n by default; with them, all objects compare unequal (except with\n themselves) and ``x.__hash__()`` returns ``id(x)``.\n\n Classes which inherit a ``__hash__()`` method from a parent class\n but change the meaning of ``__eq__()`` such that the hash value\n returned is no longer appropriate (e.g. by switching to a value-\n based concept of equality instead of the default identity based\n equality) can explicitly flag themselves as being unhashable by\n setting ``__hash__ = None`` in the class definition. Doing so means\n that not only will instances of the class raise an appropriate\n ``TypeError`` when a program attempts to retrieve their hash value,\n but they will also be correctly identified as unhashable when\n checking ``isinstance(obj, collections.Hashable)`` (unlike classes\n which define their own ``__hash__()`` to explicitly raise\n ``TypeError``).\n\n If a class that overrides ``__eq__()`` needs to retain the\n implementation of ``__hash__()`` from a parent class, the\n interpreter must be told this explicitly by setting ``__hash__ =\n .__hash__``. Otherwise the inheritance of\n ``__hash__()`` will be blocked, just as if ``__hash__`` had been\n explicitly set to ``None``.\n\nobject.__bool__(self)\n\n Called to implement truth value testing and the built-in operation\n ``bool()``; should return ``False`` or ``True``. When this method\n is not defined, ``__len__()`` is called, if it is defined, and the\n object is considered true if its result is nonzero. If a class\n defines neither ``__len__()`` nor ``__bool__()``, all its instances\n are considered true.\n', + 'debugger': '\n``pdb`` --- The Python Debugger\n*******************************\n\nThe module ``pdb`` defines an interactive source code debugger for\nPython programs. It supports setting (conditional) breakpoints and\nsingle stepping at the source line level, inspection of stack frames,\nsource code listing, and evaluation of arbitrary Python code in the\ncontext of any stack frame. It also supports post-mortem debugging\nand can be called under program control.\n\nThe debugger is extensible --- it is actually defined as the class\n``Pdb``. This is currently undocumented but easily understood by\nreading the source. The extension interface uses the modules ``bdb``\n(undocumented) and ``cmd``.\n\nThe debugger\'s prompt is ``(Pdb)``. Typical usage to run a program\nunder control of the debugger is:\n\n >>> import pdb\n >>> import mymodule\n >>> pdb.run(\'mymodule.test()\')\n > (0)?()\n (Pdb) continue\n > (1)?()\n (Pdb) continue\n NameError: \'spam\'\n > (1)?()\n (Pdb)\n\n``pdb.py`` can also be invoked as a script to debug other scripts.\nFor example:\n\n python3 -m pdb myscript.py\n\nWhen invoked as a script, pdb will automatically enter post-mortem\ndebugging if the program being debugged exits abnormally. After post-\nmortem debugging (or after normal exit of the program), pdb will\nrestart the program. Automatic restarting preserves pdb\'s state (such\nas breakpoints) and in most cases is more useful than quitting the\ndebugger upon program\'s exit.\n\nThe typical usage to break into the debugger from a running program is\nto insert\n\n import pdb; pdb.set_trace()\n\nat the location you want to break into the debugger. You can then\nstep through the code following this statement, and continue running\nwithout the debugger using the ``c`` command.\n\nThe typical usage to inspect a crashed program is:\n\n >>> import pdb\n >>> import mymodule\n >>> mymodule.test()\n Traceback (most recent call last):\n File "", line 1, in ?\n File "./mymodule.py", line 4, in test\n test2()\n File "./mymodule.py", line 3, in test2\n print(spam)\n NameError: spam\n >>> pdb.pm()\n > ./mymodule.py(3)test2()\n -> print(spam)\n (Pdb)\n\nThe module defines the following functions; each enters the debugger\nin a slightly different way:\n\npdb.run(statement[, globals[, locals]])\n\n Execute the *statement* (given as a string) under debugger control.\n The debugger prompt appears before any code is executed; you can\n set breakpoints and type ``continue``, or you can step through the\n statement using ``step`` or ``next`` (all these commands are\n explained below). The optional *globals* and *locals* arguments\n specify the environment in which the code is executed; by default\n the dictionary of the module ``__main__`` is used. (See the\n explanation of the built-in ``exec()`` or ``eval()`` functions.)\n\npdb.runeval(expression[, globals[, locals]])\n\n Evaluate the *expression* (given as a string) under debugger\n control. When ``runeval()`` returns, it returns the value of the\n expression. Otherwise this function is similar to ``run()``.\n\npdb.runcall(function[, argument, ...])\n\n Call the *function* (a function or method object, not a string)\n with the given arguments. When ``runcall()`` returns, it returns\n whatever the function call returned. The debugger prompt appears\n as soon as the function is entered.\n\npdb.set_trace()\n\n Enter the debugger at the calling stack frame. This is useful to\n hard-code a breakpoint at a given point in a program, even if the\n code is not otherwise being debugged (e.g. when an assertion\n fails).\n\npdb.post_mortem([traceback])\n\n Enter post-mortem debugging of the given *traceback* object. If no\n *traceback* is given, it uses the one of the exception that is\n currently being handled (an exception must be being handled if the\n default is to be used).\n\npdb.pm()\n\n Enter post-mortem debugging of the traceback found in\n ``sys.last_traceback``.\n\nThe ``run*`` functions and ``set_trace()`` are aliases for\ninstantiating the ``Pdb`` class and calling the method of the same\nname. If you want to access further features, you have to do this\nyourself:\n\nclass class pdb.Pdb(completekey=\'tab\', stdin=None, stdout=None, skip=None)\n\n ``Pdb`` is the debugger class.\n\n The *completekey*, *stdin* and *stdout* arguments are passed to the\n underlying ``cmd.Cmd`` class; see the description there.\n\n The *skip* argument, if given, must be an iterable of glob-style\n module name patterns. The debugger will not step into frames that\n originate in a module that matches one of these patterns. [1]\n\n Example call to enable tracing with *skip*:\n\n import pdb; pdb.Pdb(skip=[\'django.*\']).set_trace()\n\n New in version 3.1: The *skip* argument.\n\n run(statement[, globals[, locals]])\n runeval(expression[, globals[, locals]])\n runcall(function[, argument, ...])\n set_trace()\n\n See the documentation for the functions explained above.\n\n\nDebugger Commands\n=================\n\nThe debugger recognizes the following commands. Most commands can be\nabbreviated to one or two letters; e.g. ``h(elp)`` means that either\n``h`` or ``help`` can be used to enter the help command (but not\n``he`` or ``hel``, nor ``H`` or ``Help`` or ``HELP``). Arguments to\ncommands must be separated by whitespace (spaces or tabs). Optional\narguments are enclosed in square brackets (``[]``) in the command\nsyntax; the square brackets must not be typed. Alternatives in the\ncommand syntax are separated by a vertical bar (``|``).\n\nEntering a blank line repeats the last command entered. Exception: if\nthe last command was a ``list`` command, the next 11 lines are listed.\n\nCommands that the debugger doesn\'t recognize are assumed to be Python\nstatements and are executed in the context of the program being\ndebugged. Python statements can also be prefixed with an exclamation\npoint (``!``). This is a powerful way to inspect the program being\ndebugged; it is even possible to change a variable or call a function.\nWhen an exception occurs in such a statement, the exception name is\nprinted but the debugger\'s state is not changed.\n\nMultiple commands may be entered on a single line, separated by\n``;;``. (A single ``;`` is not used as it is the separator for\nmultiple commands in a line that is passed to the Python parser.) No\nintelligence is applied to separating the commands; the input is split\nat the first ``;;`` pair, even if it is in the middle of a quoted\nstring.\n\nThe debugger supports aliases. Aliases can have parameters which\nallows one a certain level of adaptability to the context under\nexamination.\n\nIf a file ``.pdbrc`` exists in the user\'s home directory or in the\ncurrent directory, it is read in and executed as if it had been typed\nat the debugger prompt. This is particularly useful for aliases. If\nboth files exist, the one in the home directory is read first and\naliases defined there can be overridden by the local file.\n\nh(elp) [*command*]\n Without argument, print the list of available commands. With a\n *command* as argument, print help about that command. ``help pdb``\n displays the full documentation file; if the environment variable\n **PAGER** is defined, the file is piped through that command\n instead. Since the *command* argument must be an identifier,\n ``help exec`` must be entered to get help on the ``!`` command.\n\nw(here)\n Print a stack trace, with the most recent frame at the bottom. An\n arrow indicates the current frame, which determines the context of\n most commands.\n\nd(own)\n Move the current frame one level down in the stack trace (to a\n newer frame).\n\nu(p)\n Move the current frame one level up in the stack trace (to an older\n frame).\n\nb(reak) [[*filename*:]*lineno* | *function*[, *condition*]]\n With a *lineno* argument, set a break there in the current file.\n With a *function* argument, set a break at the first executable\n statement within that function. The line number may be prefixed\n with a filename and a colon, to specify a breakpoint in another\n file (probably one that hasn\'t been loaded yet). The file is\n searched on ``sys.path``. Note that each breakpoint is assigned a\n number to which all the other breakpoint commands refer.\n\n If a second argument is present, it is an expression which must\n evaluate to true before the breakpoint is honored.\n\n Without argument, list all breaks, including for each breakpoint,\n the number of times that breakpoint has been hit, the current\n ignore count, and the associated condition if any.\n\ntbreak [[*filename*:]*lineno* | *function*[, *condition*]]\n Temporary breakpoint, which is removed automatically when it is\n first hit. The arguments are the same as break.\n\ncl(ear) [*filename:lineno* | *bpnumber* [*bpnumber ...*]]\n With a *filename:lineno* argument, clear all the breakpoints at\n this line. With a space separated list of breakpoint numbers, clear\n those breakpoints. Without argument, clear all breaks (but first\n ask confirmation).\n\ndisable [*bpnumber* [*bpnumber ...*]]\n Disables the breakpoints given as a space separated list of\n breakpoint numbers. Disabling a breakpoint means it cannot cause\n the program to stop execution, but unlike clearing a breakpoint, it\n remains in the list of breakpoints and can be (re-)enabled.\n\nenable [*bpnumber* [*bpnumber ...*]]\n Enables the breakpoints specified.\n\nignore *bpnumber* [*count*]\n Sets the ignore count for the given breakpoint number. If count is\n omitted, the ignore count is set to 0. A breakpoint becomes active\n when the ignore count is zero. When non-zero, the count is\n decremented each time the breakpoint is reached and the breakpoint\n is not disabled and any associated condition evaluates to true.\n\ncondition *bpnumber* [*condition*]\n Condition is an expression which must evaluate to true before the\n breakpoint is honored. If condition is absent, any existing\n condition is removed; i.e., the breakpoint is made unconditional.\n\ncommands [*bpnumber*]\n Specify a list of commands for breakpoint number *bpnumber*. The\n commands themselves appear on the following lines. Type a line\n containing just \'end\' to terminate the commands. An example:\n\n (Pdb) commands 1\n (com) print some_variable\n (com) end\n (Pdb)\n\n To remove all commands from a breakpoint, type commands and follow\n it immediately with end; that is, give no commands.\n\n With no *bpnumber* argument, commands refers to the last breakpoint\n set.\n\n You can use breakpoint commands to start your program up again.\n Simply use the continue command, or step, or any other command that\n resumes execution.\n\n Specifying any command resuming execution (currently continue,\n step, next, return, jump, quit and their abbreviations) terminates\n the command list (as if that command was immediately followed by\n end). This is because any time you resume execution (even with a\n simple next or step), you may encounter another breakpoint--which\n could have its own command list, leading to ambiguities about which\n list to execute.\n\n If you use the \'silent\' command in the command list, the usual\n message about stopping at a breakpoint is not printed. This may be\n desirable for breakpoints that are to print a specific message and\n then continue. If none of the other commands print anything, you\n see no sign that the breakpoint was reached.\n\ns(tep)\n Execute the current line, stop at the first possible occasion\n (either in a function that is called or on the next line in the\n current function).\n\nn(ext)\n Continue execution until the next line in the current function is\n reached or it returns. (The difference between ``next`` and\n ``step`` is that ``step`` stops inside a called function, while\n ``next`` executes called functions at (nearly) full speed, only\n stopping at the next line in the current function.)\n\nunt(il)\n Continue execution until the line with the line number greater than\n the current one is reached or when returning from current frame.\n\nr(eturn)\n Continue execution until the current function returns.\n\nc(ont(inue))\n Continue execution, only stop when a breakpoint is encountered.\n\nj(ump) *lineno*\n Set the next line that will be executed. Only available in the\n bottom-most frame. This lets you jump back and execute code again,\n or jump forward to skip code that you don\'t want to run.\n\n It should be noted that not all jumps are allowed --- for instance\n it is not possible to jump into the middle of a ``for`` loop or out\n of a ``finally`` clause.\n\nl(ist) [*first*[, *last*]]\n List source code for the current file. Without arguments, list 11\n lines around the current line or continue the previous listing.\n With one argument, list 11 lines around at that line. With two\n arguments, list the given range; if the second argument is less\n than the first, it is interpreted as a count.\n\na(rgs)\n Print the argument list of the current function.\n\np(rint) *expression*\n Evaluate the *expression* in the current context and print its\n value.\n\npp *expression*\n Like the ``p`` command, except the value of the expression is\n pretty-printed using the ``pprint`` module.\n\nalias [*name* [command]]\n Creates an alias called *name* that executes *command*. The\n command must *not* be enclosed in quotes. Replaceable parameters\n can be indicated by ``%1``, ``%2``, and so on, while ``%*`` is\n replaced by all the parameters. If no command is given, the\n current alias for *name* is shown. If no arguments are given, all\n aliases are listed.\n\n Aliases may be nested and can contain anything that can be legally\n typed at the pdb prompt. Note that internal pdb commands *can* be\n overridden by aliases. Such a command is then hidden until the\n alias is removed. Aliasing is recursively applied to the first\n word of the command line; all other words in the line are left\n alone.\n\n As an example, here are two useful aliases (especially when placed\n in the ``.pdbrc`` file):\n\n #Print instance variables (usage "pi classInst")\n alias pi for k in %1.__dict__.keys(): print("%1.",k,"=",%1.__dict__[k])\n #Print instance variables in self\n alias ps pi self\n\nunalias *name*\n Deletes the specified alias.\n\n[!]*statement*\n Execute the (one-line) *statement* in the context of the current\n stack frame. The exclamation point can be omitted unless the first\n word of the statement resembles a debugger command. To set a global\n variable, you can prefix the assignment command with a ``global``\n command on the same line, e.g.:\n\n (Pdb) global list_options; list_options = [\'-l\']\n (Pdb)\n\nrun [*args* ...]\n Restart the debugged Python program. If an argument is supplied, it\n is split with "shlex" and the result is used as the new sys.argv.\n History, breakpoints, actions and debugger options are preserved.\n "restart" is an alias for "run".\n\nq(uit)\n Quit from the debugger. The program being executed is aborted.\n\n-[ Footnotes ]-\n\n[1] Whether a frame is considered to originate in a certain module is\n determined by the ``__name__`` in the frame globals.\n', 'del': '\nThe ``del`` statement\n*********************\n\n del_stmt ::= "del" target_list\n\nDeletion is recursively defined very similar to the way assignment is\ndefined. Rather that spelling it out in full details, here are some\nhints.\n\nDeletion of a target list recursively deletes each target, from left\nto right.\n\nDeletion of a name removes the binding of that name from the local or\nglobal namespace, depending on whether the name occurs in a ``global``\nstatement in the same code block. If the name is unbound, a\n``NameError`` exception will be raised.\n\nIt is illegal to delete a name from the local namespace if it occurs\nas a free variable in a nested block.\n\nDeletion of attribute references, subscriptions and slicings is passed\nto the primary object involved; deletion of a slicing is in general\nequivalent to assignment of an empty slice of the right type (but even\nthis is determined by the sliced object).\n', 'dict': '\nDictionary displays\n*******************\n\nA dictionary display is a possibly empty series of key/datum pairs\nenclosed in curly braces:\n\n dict_display ::= "{" [key_datum_list | dict_comprehension] "}"\n key_datum_list ::= key_datum ("," key_datum)* [","]\n key_datum ::= expression ":" expression\n dict_comprehension ::= expression ":" expression comp_for\n\nA dictionary display yields a new dictionary object.\n\nIf a comma-separated sequence of key/datum pairs is given, they are\nevaluated from left to right to define the entries of the dictionary:\neach key object is used as a key into the dictionary to store the\ncorresponding datum. This means that you can specify the same key\nmultiple times in the key/datum list, and the final dictionary\'s value\nfor that key will be the last one given.\n\nA dict comprehension, in contrast to list and set comprehensions,\nneeds two expressions separated with a colon followed by the usual\n"for" and "if" clauses. When the comprehension is run, the resulting\nkey and value elements are inserted in the new dictionary in the order\nthey are produced.\n\nRestrictions on the types of the key values are listed earlier in\nsection *The standard type hierarchy*. (To summarize, the key type\nshould be *hashable*, which excludes all mutable objects.) Clashes\nbetween duplicate keys are not detected; the last datum (textually\nrightmost in the display) stored for a given key value prevails.\n', 'dynamic-features': '\nInteraction with dynamic features\n*********************************\n\nThere are several cases where Python statements are illegal when used\nin conjunction with nested scopes that contain free variables.\n\nIf a variable is referenced in an enclosing scope, it is illegal to\ndelete the name. An error will be reported at compile time.\n\nIf the wild card form of import --- ``import *`` --- is used in a\nfunction and the function contains or is a nested block with free\nvariables, the compiler will raise a ``SyntaxError``.\n\nThe ``eval()`` and ``exec()`` functions do not have access to the full\nenvironment for resolving names. Names may be resolved in the local\nand global namespaces of the caller. Free variables are not resolved\nin the nearest enclosing namespace, but in the global namespace. [1]\nThe ``exec()`` and ``eval()`` functions have optional arguments to\noverride the global and local namespace. If only one namespace is\nspecified, it is used for both.\n', 'else': '\nThe ``if`` statement\n********************\n\nThe ``if`` statement is used for conditional execution:\n\n if_stmt ::= "if" expression ":" suite\n ( "elif" expression ":" suite )*\n ["else" ":" suite]\n\nIt selects exactly one of the suites by evaluating the expressions one\nby one until one is found to be true (see section *Boolean operations*\nfor the definition of true and false); then that suite is executed\n(and no other part of the ``if`` statement is executed or evaluated).\nIf all expressions are false, the suite of the ``else`` clause, if\npresent, is executed.\n', 'exceptions': '\nExceptions\n**********\n\nExceptions are a means of breaking out of the normal flow of control\nof a code block in order to handle errors or other exceptional\nconditions. An exception is *raised* at the point where the error is\ndetected; it may be *handled* by the surrounding code block or by any\ncode block that directly or indirectly invoked the code block where\nthe error occurred.\n\nThe Python interpreter raises an exception when it detects a run-time\nerror (such as division by zero). A Python program can also\nexplicitly raise an exception with the ``raise`` statement. Exception\nhandlers are specified with the ``try`` ... ``except`` statement. The\n``finally`` clause of such a statement can be used to specify cleanup\ncode which does not handle the exception, but is executed whether an\nexception occurred or not in the preceding code.\n\nPython uses the "termination" model of error handling: an exception\nhandler can find out what happened and continue execution at an outer\nlevel, but it cannot repair the cause of the error and retry the\nfailing operation (except by re-entering the offending piece of code\nfrom the top).\n\nWhen an exception is not handled at all, the interpreter terminates\nexecution of the program, or returns to its interactive main loop. In\neither case, it prints a stack backtrace, except when the exception is\n``SystemExit``.\n\nExceptions are identified by class instances. The ``except`` clause\nis selected depending on the class of the instance: it must reference\nthe class of the instance or a base class thereof. The instance can\nbe received by the handler and can carry additional information about\nthe exceptional condition.\n\nNote: Exception messages are not part of the Python API. Their contents\n may change from one version of Python to the next without warning\n and should not be relied on by code which will run under multiple\n versions of the interpreter.\n\nSee also the description of the ``try`` statement in section *The try\nstatement* and ``raise`` statement in section *The raise statement*.\n\n-[ Footnotes ]-\n\n[1] This limitation occurs because the code that is executed by these\n operations is not available at the time the module is compiled.\n', - 'execmodel': '\nExecution model\n***************\n\n\nNaming and binding\n==================\n\n*Names* refer to objects. Names are introduced by name binding\noperations. Each occurrence of a name in the program text refers to\nthe *binding* of that name established in the innermost function block\ncontaining the use.\n\nA *block* is a piece of Python program text that is executed as a\nunit. The following are blocks: a module, a function body, and a class\ndefinition. Each command typed interactively is a block. A script\nfile (a file given as standard input to the interpreter or specified\non the interpreter command line the first argument) is a code block.\nA script command (a command specified on the interpreter command line\nwith the \'**-c**\' option) is a code block. The string argument passed\nto the built-in functions ``eval()`` and ``exec()`` is a code block.\n\nA code block is executed in an *execution frame*. A frame contains\nsome administrative information (used for debugging) and determines\nwhere and how execution continues after the code block\'s execution has\ncompleted.\n\nA *scope* defines the visibility of a name within a block. If a local\nvariable is defined in a block, its scope includes that block. If the\ndefinition occurs in a function block, the scope extends to any blocks\ncontained within the defining one, unless a contained block introduces\na different binding for the name. The scope of names defined in a\nclass block is limited to the class block; it does not extend to the\ncode blocks of methods -- this includes comprehensions and generator\nexpressions since they are implemented using a function scope. This\nmeans that the following will fail:\n\n class A:\n a = 42\n b = list(a + i for i in range(10))\n\nWhen a name is used in a code block, it is resolved using the nearest\nenclosing scope. The set of all such scopes visible to a code block\nis called the block\'s *environment*.\n\nIf a name is bound in a block, it is a local variable of that block,\nunless declared as ``nonlocal``. If a name is bound at the module\nlevel, it is a global variable. (The variables of the module code\nblock are local and global.) If a variable is used in a code block\nbut not defined there, it is a *free variable*.\n\nWhen a name is not found at all, a ``NameError`` exception is raised.\nIf the name refers to a local variable that has not been bound, a\n``UnboundLocalError`` exception is raised. ``UnboundLocalError`` is a\nsubclass of ``NameError``.\n\nThe following constructs bind names: formal parameters to functions,\n``import`` statements, class and function definitions (these bind the\nclass or function name in the defining block), and targets that are\nidentifiers if occurring in an assignment, ``for`` loop header, or\nafter ``as`` in a ``with`` statement or :keyword.`except` clause. The\n``import`` statement of the form ``from ... import *`` binds all names\ndefined in the imported module, except those beginning with an\nunderscore. This form may only be used at the module level.\n\nA target occurring in a ``del`` statement is also considered bound for\nthis purpose (though the actual semantics are to unbind the name). It\nis illegal to unbind a name that is referenced by an enclosing scope;\nthe compiler will report a ``SyntaxError``.\n\nEach assignment or import statement occurs within a block defined by a\nclass or function definition or at the module level (the top-level\ncode block).\n\nIf a name binding operation occurs anywhere within a code block, all\nuses of the name within the block are treated as references to the\ncurrent block. This can lead to errors when a name is used within a\nblock before it is bound. This rule is subtle. Python lacks\ndeclarations and allows name binding operations to occur anywhere\nwithin a code block. The local variables of a code block can be\ndetermined by scanning the entire text of the block for name binding\noperations.\n\nIf the ``global`` statement occurs within a block, all uses of the\nname specified in the statement refer to the binding of that name in\nthe top-level namespace. Names are resolved in the top-level\nnamespace by searching the global namespace, i.e. the namespace of the\nmodule containing the code block, and the builtin namespace, the\nnamespace of the module ``builtins``. The global namespace is\nsearched first. If the name is not found there, the builtin namespace\nis searched. The global statement must precede all uses of the name.\n\nThe built-in namespace associated with the execution of a code block\nis actually found by looking up the name ``__builtins__`` in its\nglobal namespace; this should be a dictionary or a module (in the\nlatter case the module\'s dictionary is used). By default, when in the\n``__main__`` module, ``__builtins__`` is the built-in module\n``builtins``; when in any other module, ``__builtins__`` is an alias\nfor the dictionary of the ``builtins`` module itself.\n``__builtins__`` can be set to a user-created dictionary to create a\nweak form of restricted execution.\n\nNote: Users should not touch ``__builtins__``; it is strictly an\n implementation detail. Users wanting to override values in the\n built-in namespace should ``import`` the ``builtins`` module and\n modify its attributes appropriately.\n\nThe namespace for a module is automatically created the first time a\nmodule is imported. The main module for a script is always called\n``__main__``.\n\nThe global statement has the same scope as a name binding operation in\nthe same block. If the nearest enclosing scope for a free variable\ncontains a global statement, the free variable is treated as a global.\n\nA class definition is an executable statement that may use and define\nnames. These references follow the normal rules for name resolution.\nThe namespace of the class definition becomes the attribute dictionary\nof the class. Names defined at the class scope are not visible in\nmethods.\n\n\nInteraction with dynamic features\n---------------------------------\n\nThere are several cases where Python statements are illegal when used\nin conjunction with nested scopes that contain free variables.\n\nIf a variable is referenced in an enclosing scope, it is illegal to\ndelete the name. An error will be reported at compile time.\n\nIf the wild card form of import --- ``import *`` --- is used in a\nfunction and the function contains or is a nested block with free\nvariables, the compiler will raise a ``SyntaxError``.\n\nThe ``eval()`` and ``exec()`` functions do not have access to the full\nenvironment for resolving names. Names may be resolved in the local\nand global namespaces of the caller. Free variables are not resolved\nin the nearest enclosing namespace, but in the global namespace. [1]\nThe ``exec()`` and ``eval()`` functions have optional arguments to\noverride the global and local namespace. If only one namespace is\nspecified, it is used for both.\n\n\nExceptions\n==========\n\nExceptions are a means of breaking out of the normal flow of control\nof a code block in order to handle errors or other exceptional\nconditions. An exception is *raised* at the point where the error is\ndetected; it may be *handled* by the surrounding code block or by any\ncode block that directly or indirectly invoked the code block where\nthe error occurred.\n\nThe Python interpreter raises an exception when it detects a run-time\nerror (such as division by zero). A Python program can also\nexplicitly raise an exception with the ``raise`` statement. Exception\nhandlers are specified with the ``try`` ... ``except`` statement. The\n``finally`` clause of such a statement can be used to specify cleanup\ncode which does not handle the exception, but is executed whether an\nexception occurred or not in the preceding code.\n\nPython uses the "termination" model of error handling: an exception\nhandler can find out what happened and continue execution at an outer\nlevel, but it cannot repair the cause of the error and retry the\nfailing operation (except by re-entering the offending piece of code\nfrom the top).\n\nWhen an exception is not handled at all, the interpreter terminates\nexecution of the program, or returns to its interactive main loop. In\neither case, it prints a stack backtrace, except when the exception is\n``SystemExit``.\n\nExceptions are identified by class instances. The ``except`` clause\nis selected depending on the class of the instance: it must reference\nthe class of the instance or a base class thereof. The instance can\nbe received by the handler and can carry additional information about\nthe exceptional condition.\n\nNote: Exception messages are not part of the Python API. Their contents\n may change from one version of Python to the next without warning\n and should not be relied on by code which will run under multiple\n versions of the interpreter.\n\nSee also the description of the ``try`` statement in section *The try\nstatement* and ``raise`` statement in section *The raise statement*.\n\n-[ Footnotes ]-\n\n[1] This limitation occurs because the code that is executed by these\n operations is not available at the time the module is compiled.\n', + 'execmodel': '\nExecution model\n***************\n\n\nNaming and binding\n==================\n\n*Names* refer to objects. Names are introduced by name binding\noperations. Each occurrence of a name in the program text refers to\nthe *binding* of that name established in the innermost function block\ncontaining the use.\n\nA *block* is a piece of Python program text that is executed as a\nunit. The following are blocks: a module, a function body, and a class\ndefinition. Each command typed interactively is a block. A script\nfile (a file given as standard input to the interpreter or specified\non the interpreter command line the first argument) is a code block.\nA script command (a command specified on the interpreter command line\nwith the \'**-c**\' option) is a code block. The string argument passed\nto the built-in functions ``eval()`` and ``exec()`` is a code block.\n\nA code block is executed in an *execution frame*. A frame contains\nsome administrative information (used for debugging) and determines\nwhere and how execution continues after the code block\'s execution has\ncompleted.\n\nA *scope* defines the visibility of a name within a block. If a local\nvariable is defined in a block, its scope includes that block. If the\ndefinition occurs in a function block, the scope extends to any blocks\ncontained within the defining one, unless a contained block introduces\na different binding for the name. The scope of names defined in a\nclass block is limited to the class block; it does not extend to the\ncode blocks of methods -- this includes comprehensions and generator\nexpressions since they are implemented using a function scope. This\nmeans that the following will fail:\n\n class A:\n a = 42\n b = list(a + i for i in range(10))\n\nWhen a name is used in a code block, it is resolved using the nearest\nenclosing scope. The set of all such scopes visible to a code block\nis called the block\'s *environment*.\n\nIf a name is bound in a block, it is a local variable of that block,\nunless declared as ``nonlocal``. If a name is bound at the module\nlevel, it is a global variable. (The variables of the module code\nblock are local and global.) If a variable is used in a code block\nbut not defined there, it is a *free variable*.\n\nWhen a name is not found at all, a ``NameError`` exception is raised.\nIf the name refers to a local variable that has not been bound, a\n``UnboundLocalError`` exception is raised. ``UnboundLocalError`` is a\nsubclass of ``NameError``.\n\nThe following constructs bind names: formal parameters to functions,\n``import`` statements, class and function definitions (these bind the\nclass or function name in the defining block), and targets that are\nidentifiers if occurring in an assignment, ``for`` loop header, or\nafter ``as`` in a ``with`` statement or ``except`` clause. The\n``import`` statement of the form ``from ... import *`` binds all names\ndefined in the imported module, except those beginning with an\nunderscore. This form may only be used at the module level.\n\nA target occurring in a ``del`` statement is also considered bound for\nthis purpose (though the actual semantics are to unbind the name). It\nis illegal to unbind a name that is referenced by an enclosing scope;\nthe compiler will report a ``SyntaxError``.\n\nEach assignment or import statement occurs within a block defined by a\nclass or function definition or at the module level (the top-level\ncode block).\n\nIf a name binding operation occurs anywhere within a code block, all\nuses of the name within the block are treated as references to the\ncurrent block. This can lead to errors when a name is used within a\nblock before it is bound. This rule is subtle. Python lacks\ndeclarations and allows name binding operations to occur anywhere\nwithin a code block. The local variables of a code block can be\ndetermined by scanning the entire text of the block for name binding\noperations.\n\nIf the ``global`` statement occurs within a block, all uses of the\nname specified in the statement refer to the binding of that name in\nthe top-level namespace. Names are resolved in the top-level\nnamespace by searching the global namespace, i.e. the namespace of the\nmodule containing the code block, and the builtins namespace, the\nnamespace of the module ``builtins``. The global namespace is\nsearched first. If the name is not found there, the builtins\nnamespace is searched. The global statement must precede all uses of\nthe name.\n\nThe builtins namespace associated with the execution of a code block\nis actually found by looking up the name ``__builtins__`` in its\nglobal namespace; this should be a dictionary or a module (in the\nlatter case the module\'s dictionary is used). By default, when in the\n``__main__`` module, ``__builtins__`` is the built-in module\n``builtins``; when in any other module, ``__builtins__`` is an alias\nfor the dictionary of the ``builtins`` module itself.\n``__builtins__`` can be set to a user-created dictionary to create a\nweak form of restricted execution.\n\n**CPython implementation detail:** Users should not touch\n``__builtins__``; it is strictly an implementation detail. Users\nwanting to override values in the builtins namespace should ``import``\nthe ``builtins`` module and modify its attributes appropriately.\n\nThe namespace for a module is automatically created the first time a\nmodule is imported. The main module for a script is always called\n``__main__``.\n\nThe ``global`` statement has the same scope as a name binding\noperation in the same block. If the nearest enclosing scope for a\nfree variable contains a global statement, the free variable is\ntreated as a global.\n\nA class definition is an executable statement that may use and define\nnames. These references follow the normal rules for name resolution.\nThe namespace of the class definition becomes the attribute dictionary\nof the class. Names defined at the class scope are not visible in\nmethods.\n\n\nInteraction with dynamic features\n---------------------------------\n\nThere are several cases where Python statements are illegal when used\nin conjunction with nested scopes that contain free variables.\n\nIf a variable is referenced in an enclosing scope, it is illegal to\ndelete the name. An error will be reported at compile time.\n\nIf the wild card form of import --- ``import *`` --- is used in a\nfunction and the function contains or is a nested block with free\nvariables, the compiler will raise a ``SyntaxError``.\n\nThe ``eval()`` and ``exec()`` functions do not have access to the full\nenvironment for resolving names. Names may be resolved in the local\nand global namespaces of the caller. Free variables are not resolved\nin the nearest enclosing namespace, but in the global namespace. [1]\nThe ``exec()`` and ``eval()`` functions have optional arguments to\noverride the global and local namespace. If only one namespace is\nspecified, it is used for both.\n\n\nExceptions\n==========\n\nExceptions are a means of breaking out of the normal flow of control\nof a code block in order to handle errors or other exceptional\nconditions. An exception is *raised* at the point where the error is\ndetected; it may be *handled* by the surrounding code block or by any\ncode block that directly or indirectly invoked the code block where\nthe error occurred.\n\nThe Python interpreter raises an exception when it detects a run-time\nerror (such as division by zero). A Python program can also\nexplicitly raise an exception with the ``raise`` statement. Exception\nhandlers are specified with the ``try`` ... ``except`` statement. The\n``finally`` clause of such a statement can be used to specify cleanup\ncode which does not handle the exception, but is executed whether an\nexception occurred or not in the preceding code.\n\nPython uses the "termination" model of error handling: an exception\nhandler can find out what happened and continue execution at an outer\nlevel, but it cannot repair the cause of the error and retry the\nfailing operation (except by re-entering the offending piece of code\nfrom the top).\n\nWhen an exception is not handled at all, the interpreter terminates\nexecution of the program, or returns to its interactive main loop. In\neither case, it prints a stack backtrace, except when the exception is\n``SystemExit``.\n\nExceptions are identified by class instances. The ``except`` clause\nis selected depending on the class of the instance: it must reference\nthe class of the instance or a base class thereof. The instance can\nbe received by the handler and can carry additional information about\nthe exceptional condition.\n\nNote: Exception messages are not part of the Python API. Their contents\n may change from one version of Python to the next without warning\n and should not be relied on by code which will run under multiple\n versions of the interpreter.\n\nSee also the description of the ``try`` statement in section *The try\nstatement* and ``raise`` statement in section *The raise statement*.\n\n-[ Footnotes ]-\n\n[1] This limitation occurs because the code that is executed by these\n operations is not available at the time the module is compiled.\n', 'exprlists': '\nExpression lists\n****************\n\n expression_list ::= expression ( "," expression )* [","]\n\nAn expression list containing at least one comma yields a tuple. The\nlength of the tuple is the number of expressions in the list. The\nexpressions are evaluated from left to right.\n\nThe trailing comma is required only to create a single tuple (a.k.a. a\n*singleton*); it is optional in all other cases. A single expression\nwithout a trailing comma doesn\'t create a tuple, but rather yields the\nvalue of that expression. (To create an empty tuple, use an empty pair\nof parentheses: ``()``.)\n', 'floating': '\nFloating point literals\n***********************\n\nFloating point literals are described by the following lexical\ndefinitions:\n\n floatnumber ::= pointfloat | exponentfloat\n pointfloat ::= [intpart] fraction | intpart "."\n exponentfloat ::= (intpart | pointfloat) exponent\n intpart ::= digit+\n fraction ::= "." digit+\n exponent ::= ("e" | "E") ["+" | "-"] digit+\n\nNote that the integer and exponent parts are always interpreted using\nradix 10. For example, ``077e010`` is legal, and denotes the same\nnumber as ``77e10``. The allowed range of floating point literals is\nimplementation-dependent. Some examples of floating point literals:\n\n 3.14 10. .001 1e100 3.14e-10 0e0\n\nNote that numeric literals do not include a sign; a phrase like ``-1``\nis actually an expression composed of the unary operator ``-`` and the\nliteral ``1``.\n', 'for': '\nThe ``for`` statement\n*********************\n\nThe ``for`` statement is used to iterate over the elements of a\nsequence (such as a string, tuple or list) or other iterable object:\n\n for_stmt ::= "for" target_list "in" expression_list ":" suite\n ["else" ":" suite]\n\nThe expression list is evaluated once; it should yield an iterable\nobject. An iterator is created for the result of the\n``expression_list``. The suite is then executed once for each item\nprovided by the iterator, in the order of ascending indices. Each\nitem in turn is assigned to the target list using the standard rules\nfor assignments (see *Assignment statements*), and then the suite is\nexecuted. When the items are exhausted (which is immediately when the\nsequence is empty or an iterator raises a ``StopIteration``\nexception), the suite in the ``else`` clause, if present, is executed,\nand the loop terminates.\n\nA ``break`` statement executed in the first suite terminates the loop\nwithout executing the ``else`` clause\'s suite. A ``continue``\nstatement executed in the first suite skips the rest of the suite and\ncontinues with the next item, or with the ``else`` clause if there was\nno next item.\n\nThe suite may assign to the variable(s) in the target list; this does\nnot affect the next item assigned to it.\n\nNames in the target list are not deleted when the loop is finished,\nbut if the sequence is empty, it will not have been assigned to at all\nby the loop. Hint: the built-in function ``range()`` returns an\niterator of integers suitable to emulate the effect of Pascal\'s ``for\ni := a to b do``; e.g., ``list(range(3))`` returns the list ``[0, 1,\n2]``.\n\nNote: There is a subtlety when the sequence is being modified by the loop\n (this can only occur for mutable sequences, i.e. lists). An\n internal counter is used to keep track of which item is used next,\n and this is incremented on each iteration. When this counter has\n reached the length of the sequence the loop terminates. This means\n that if the suite deletes the current (or a previous) item from the\n sequence, the next item will be skipped (since it gets the index of\n the current item which has already been treated). Likewise, if the\n suite inserts an item in the sequence before the current item, the\n current item will be treated again the next time through the loop.\n This can lead to nasty bugs that can be avoided by making a\n temporary copy using a slice of the whole sequence, e.g.,\n\n for x in a[:]:\n if x < 0: a.remove(x)\n', - 'formatstrings': '\nFormat String Syntax\n********************\n\nThe ``str.format()`` method and the ``Formatter`` class share the same\nsyntax for format strings (although in the case of ``Formatter``,\nsubclasses can define their own format string syntax.)\n\nFormat strings contain "replacement fields" surrounded by curly braces\n``{}``. Anything that is not contained in braces is considered literal\ntext, which is copied unchanged to the output. If you need to include\na brace character in the literal text, it can be escaped by doubling:\n``{{`` and ``}}``.\n\nThe grammar for a replacement field is as follows:\n\n replacement_field ::= "{" field_name ["!" conversion] [":" format_spec] "}"\n field_name ::= arg_name ("." attribute_name | "[" element_index "]")*\n arg_name ::= (identifier | integer)?\n attribute_name ::= identifier\n element_index ::= integer\n conversion ::= "r" | "s" | "a"\n format_spec ::= \n\nIn less formal terms, the replacement field starts with a *field_name*\nthat specifies the object whose value is to be formatted and inserted\ninto the output instead of the replacement field. The *field_name* is\noptionally followed by a *conversion* field, which is preceded by an\nexclamation point ``\'!\'``, and a *format_spec*, which is preceded by a\ncolon ``\':\'``. These specify a non-default format for the replacement\nvalue.\n\nThe *field_name* itself begins with an *arg_name* that is either\neither a number or a keyword. If it\'s a number, it refers to a\npositional argument, and if it\'s a keyword, it refers to a named\nkeyword argument. If the numerical arg_names in a format string are\n0, 1, 2, ... in sequence, they can all be omitted (not just some) and\nthe numbers 0, 1, 2, ... will be automatically inserted in that order.\nThe *arg_name* can be followed by any number of index or attribute\nexpressions. An expression of the form ``\'.name\'`` selects the named\nattribute using ``getattr()``, while an expression of the form\n``\'[index]\'`` does an index lookup using ``__getitem__()``.\n\nSome simple format string examples:\n\n "First, thou shalt count to {0}" # References first positional argument\n "Bring me a {}" # Implicitly references the first positional argument\n "From {} to {}" # Same as "From {0] to {1}"\n "My quest is {name}" # References keyword argument \'name\'\n "Weight in tons {0.weight}" # \'weight\' attribute of first positional arg\n "Units destroyed: {players[0]}" # First element of keyword argument \'players\'.\n\nThe *conversion* field causes a type coercion before formatting.\nNormally, the job of formatting a value is done by the\n``__format__()`` method of the value itself. However, in some cases\nit is desirable to force a type to be formatted as a string,\noverriding its own definition of formatting. By converting the value\nto a string before calling ``__format__()``, the normal formatting\nlogic is bypassed.\n\nThree conversion flags are currently supported: ``\'!s\'`` which calls\n``str()`` on the value, ``\'!r\'`` which calls ``repr()`` and ``\'!a\'``\nwhich calls ``ascii()``.\n\nSome examples:\n\n "Harold\'s a clever {0!s}" # Calls str() on the argument first\n "Bring out the holy {name!r}" # Calls repr() on the argument first\n\nThe *format_spec* field contains a specification of how the value\nshould be presented, including such details as field width, alignment,\npadding, decimal precision and so on. Each value type can define it\'s\nown "formatting mini-language" or interpretation of the *format_spec*.\n\nMost built-in types support a common formatting mini-language, which\nis described in the next section.\n\nA *format_spec* field can also include nested replacement fields\nwithin it. These nested replacement fields can contain only a field\nname; conversion flags and format specifications are not allowed. The\nreplacement fields within the format_spec are substituted before the\n*format_spec* string is interpreted. This allows the formatting of a\nvalue to be dynamically specified.\n\nFor example, suppose you wanted to have a replacement field whose\nfield width is determined by another variable:\n\n "A man with two {0:{1}}".format("noses", 10)\n\nThis would first evaluate the inner replacement field, making the\nformat string effectively:\n\n "A man with two {0:10}"\n\nThen the outer replacement field would be evaluated, producing:\n\n "noses "\n\nWhich is substituted into the string, yielding:\n\n "A man with two noses "\n\n(The extra space is because we specified a field width of 10, and\nbecause left alignment is the default for strings.)\n\n\nFormat Specification Mini-Language\n==================================\n\n"Format specifications" are used within replacement fields contained\nwithin a format string to define how individual values are presented\n(see *Format String Syntax*.) They can also be passed directly to the\nbuiltin ``format()`` function. Each formattable type may define how\nthe format specification is to be interpreted.\n\nMost built-in types implement the following options for format\nspecifications, although some of the formatting options are only\nsupported by the numeric types.\n\nA general convention is that an empty format string (``""``) produces\nthe same result as if you had called ``str()`` on the value.\n\nThe general form of a *standard format specifier* is:\n\n format_spec ::= [[fill]align][sign][#][0][width][.precision][type]\n fill ::= \n align ::= "<" | ">" | "=" | "^"\n sign ::= "+" | "-" | " "\n width ::= integer\n precision ::= integer\n type ::= "b" | "c" | "d" | "e" | "E" | "f" | "F" | "g" | "G" | "n" | "o" | "x" | "X" | "%"\n\nThe *fill* character can be any character other than \'}\' (which\nsignifies the end of the field). The presence of a fill character is\nsignaled by the *next* character, which must be one of the alignment\noptions. If the second character of *format_spec* is not a valid\nalignment option, then it is assumed that both the fill character and\nthe alignment option are absent.\n\nThe meaning of the various alignment options is as follows:\n\n +-----------+------------------------------------------------------------+\n | Option | Meaning |\n +===========+============================================================+\n | ``\'<\'`` | Forces the field to be left-aligned within the available |\n | | space (This is the default.) |\n +-----------+------------------------------------------------------------+\n | ``\'>\'`` | Forces the field to be right-aligned within the available |\n | | space. |\n +-----------+------------------------------------------------------------+\n | ``\'=\'`` | Forces the padding to be placed after the sign (if any) |\n | | but before the digits. This is used for printing fields |\n | | in the form \'+000000120\'. This alignment option is only |\n | | valid for numeric types. |\n +-----------+------------------------------------------------------------+\n | ``\'^\'`` | Forces the field to be centered within the available |\n | | space. |\n +-----------+------------------------------------------------------------+\n\nNote that unless a minimum field width is defined, the field width\nwill always be the same size as the data to fill it, so that the\nalignment option has no meaning in this case.\n\nThe *sign* option is only valid for number types, and can be one of\nthe following:\n\n +-----------+------------------------------------------------------------+\n | Option | Meaning |\n +===========+============================================================+\n | ``\'+\'`` | indicates that a sign should be used for both positive as |\n | | well as negative numbers. |\n +-----------+------------------------------------------------------------+\n | ``\'-\'`` | indicates that a sign should be used only for negative |\n | | numbers (this is the default behavior). |\n +-----------+------------------------------------------------------------+\n | space | indicates that a leading space should be used on positive |\n | | numbers, and a minus sign on negative numbers. |\n +-----------+------------------------------------------------------------+\n\nThe ``\'#\'`` option is only valid for integers, and only for binary,\noctal, or hexadecimal output. If present, it specifies that the\noutput will be prefixed by ``\'0b\'``, ``\'0o\'``, or ``\'0x\'``,\nrespectively.\n\n*width* is a decimal integer defining the minimum field width. If not\nspecified, then the field width will be determined by the content.\n\nIf the *width* field is preceded by a zero (``\'0\'``) character, this\nenables zero-padding. This is equivalent to an *alignment* type of\n``\'=\'`` and a *fill* character of ``\'0\'``.\n\nThe *precision* is a decimal number indicating how many digits should\nbe displayed after the decimal point for a floating point value\nformatted with ``\'f\'`` and ``\'F\'``, or before and after the decimal\npoint for a floating point value formatted with ``\'g\'`` or ``\'G\'``.\nFor non-number types the field indicates the maximum field size - in\nother words, how many characters will be used from the field content.\nThe *precision* is not allowed for integer values.\n\nFinally, the *type* determines how the data should be presented.\n\nThe available integer presentation types are:\n\n +-----------+------------------------------------------------------------+\n | Type | Meaning |\n +===========+============================================================+\n | ``\'b\'`` | Binary format. Outputs the number in base 2. |\n +-----------+------------------------------------------------------------+\n | ``\'c\'`` | Character. Converts the integer to the corresponding |\n | | unicode character before printing. |\n +-----------+------------------------------------------------------------+\n | ``\'d\'`` | Decimal Integer. Outputs the number in base 10. |\n +-----------+------------------------------------------------------------+\n | ``\'o\'`` | Octal format. Outputs the number in base 8. |\n +-----------+------------------------------------------------------------+\n | ``\'x\'`` | Hex format. Outputs the number in base 16, using lower- |\n | | case letters for the digits above 9. |\n +-----------+------------------------------------------------------------+\n | ``\'X\'`` | Hex format. Outputs the number in base 16, using upper- |\n | | case letters for the digits above 9. |\n +-----------+------------------------------------------------------------+\n | ``\'n\'`` | Number. This is the same as ``\'d\'``, except that it uses |\n | | the current locale setting to insert the appropriate |\n | | number separator characters. |\n +-----------+------------------------------------------------------------+\n | None | The same as ``\'d\'``. |\n +-----------+------------------------------------------------------------+\n\nThe available presentation types for floating point and decimal values\nare:\n\n +-----------+------------------------------------------------------------+\n | Type | Meaning |\n +===========+============================================================+\n | ``\'e\'`` | Exponent notation. Prints the number in scientific |\n | | notation using the letter \'e\' to indicate the exponent. |\n +-----------+------------------------------------------------------------+\n | ``\'E\'`` | Exponent notation. Same as ``\'e\'`` except it uses an upper |\n | | case \'E\' as the separator character. |\n +-----------+------------------------------------------------------------+\n | ``\'f\'`` | Fixed point. Displays the number as a fixed-point number. |\n +-----------+------------------------------------------------------------+\n | ``\'F\'`` | Fixed point. Same as ``\'f\'``, but converts ``nan`` to |\n | | ``NAN`` and ``inf`` to ``INF``. |\n +-----------+------------------------------------------------------------+\n | ``\'g\'`` | General format. This prints the number as a fixed-point |\n | | number, unless the number is too large, in which case it |\n | | switches to ``\'e\'`` exponent notation. Infinity and NaN |\n | | values are formatted as ``inf``, ``-inf`` and ``nan``, |\n | | respectively. |\n +-----------+------------------------------------------------------------+\n | ``\'G\'`` | General format. Same as ``\'g\'`` except switches to ``\'E\'`` |\n | | if the number gets to large. The representations of |\n | | infinity and NaN are uppercased, too. |\n +-----------+------------------------------------------------------------+\n | ``\'n\'`` | Number. This is the same as ``\'g\'``, except that it uses |\n | | the current locale setting to insert the appropriate |\n | | number separator characters. |\n +-----------+------------------------------------------------------------+\n | ``\'%\'`` | Percentage. Multiplies the number by 100 and displays in |\n | | fixed (``\'f\'``) format, followed by a percent sign. |\n +-----------+------------------------------------------------------------+\n | None | Similar to ``\'g\'``, except with at least one digit past |\n | | the decimal point and a default precision of 12. This is |\n | | intended to match ``str()``, except you can add the other |\n | | format modifiers. |\n +-----------+------------------------------------------------------------+\n', + 'formatstrings': '\nFormat String Syntax\n********************\n\nThe ``str.format()`` method and the ``Formatter`` class share the same\nsyntax for format strings (although in the case of ``Formatter``,\nsubclasses can define their own format string syntax).\n\nFormat strings contain "replacement fields" surrounded by curly braces\n``{}``. Anything that is not contained in braces is considered literal\ntext, which is copied unchanged to the output. If you need to include\na brace character in the literal text, it can be escaped by doubling:\n``{{`` and ``}}``.\n\nThe grammar for a replacement field is as follows:\n\n replacement_field ::= "{" [field_name] ["!" conversion] [":" format_spec] "}"\n field_name ::= arg_name ("." attribute_name | "[" element_index "]")*\n arg_name ::= [identifier | integer]\n attribute_name ::= identifier\n element_index ::= integer | index_string\n index_string ::= +\n conversion ::= "r" | "s" | "a"\n format_spec ::= \n\nIn less formal terms, the replacement field can start with a\n*field_name* that specifies the object whose value is to be formatted\nand inserted into the output instead of the replacement field. The\n*field_name* is optionally followed by a *conversion* field, which is\npreceded by an exclamation point ``\'!\'``, and a *format_spec*, which\nis preceded by a colon ``\':\'``. These specify a non-default format\nfor the replacement value.\n\nSee also the *Format Specification Mini-Language* section.\n\nThe *field_name* itself begins with an *arg_name* that is either\neither a number or a keyword. If it\'s a number, it refers to a\npositional argument, and if it\'s a keyword, it refers to a named\nkeyword argument. If the numerical arg_names in a format string are\n0, 1, 2, ... in sequence, they can all be omitted (not just some) and\nthe numbers 0, 1, 2, ... will be automatically inserted in that order.\nThe *arg_name* can be followed by any number of index or attribute\nexpressions. An expression of the form ``\'.name\'`` selects the named\nattribute using ``getattr()``, while an expression of the form\n``\'[index]\'`` does an index lookup using ``__getitem__()``.\n\nChanged in version 3.1: The positional argument specifiers can be\nomitted, so ``\'{} {}\'`` is equivalent to ``\'{0} {1}\'``.\n\nSome simple format string examples:\n\n "First, thou shalt count to {0}" # References first positional argument\n "Bring me a {}" # Implicitly references the first positional argument\n "From {} to {}" # Same as "From {0} to {1}"\n "My quest is {name}" # References keyword argument \'name\'\n "Weight in tons {0.weight}" # \'weight\' attribute of first positional arg\n "Units destroyed: {players[0]}" # First element of keyword argument \'players\'.\n\nThe *conversion* field causes a type coercion before formatting.\nNormally, the job of formatting a value is done by the\n``__format__()`` method of the value itself. However, in some cases\nit is desirable to force a type to be formatted as a string,\noverriding its own definition of formatting. By converting the value\nto a string before calling ``__format__()``, the normal formatting\nlogic is bypassed.\n\nThree conversion flags are currently supported: ``\'!s\'`` which calls\n``str()`` on the value, ``\'!r\'`` which calls ``repr()`` and ``\'!a\'``\nwhich calls ``ascii()``.\n\nSome examples:\n\n "Harold\'s a clever {0!s}" # Calls str() on the argument first\n "Bring out the holy {name!r}" # Calls repr() on the argument first\n "More {!a}" # Calls ascii() on the argument first\n\nThe *format_spec* field contains a specification of how the value\nshould be presented, including such details as field width, alignment,\npadding, decimal precision and so on. Each value type can define its\nown "formatting mini-language" or interpretation of the *format_spec*.\n\nMost built-in types support a common formatting mini-language, which\nis described in the next section.\n\nA *format_spec* field can also include nested replacement fields\nwithin it. These nested replacement fields can contain only a field\nname; conversion flags and format specifications are not allowed. The\nreplacement fields within the format_spec are substituted before the\n*format_spec* string is interpreted. This allows the formatting of a\nvalue to be dynamically specified.\n\nSee the *Format examples* section for some examples.\n\n\nFormat Specification Mini-Language\n==================================\n\n"Format specifications" are used within replacement fields contained\nwithin a format string to define how individual values are presented\n(see *Format String Syntax*). They can also be passed directly to the\nbuilt-in ``format()`` function. Each formattable type may define how\nthe format specification is to be interpreted.\n\nMost built-in types implement the following options for format\nspecifications, although some of the formatting options are only\nsupported by the numeric types.\n\nA general convention is that an empty format string (``""``) produces\nthe same result as if you had called ``str()`` on the value. A non-\nempty format string typically modifies the result.\n\nThe general form of a *standard format specifier* is:\n\n format_spec ::= [[fill]align][sign][#][0][width][,][.precision][type]\n fill ::= \n align ::= "<" | ">" | "=" | "^"\n sign ::= "+" | "-" | " "\n width ::= integer\n precision ::= integer\n type ::= "b" | "c" | "d" | "e" | "E" | "f" | "F" | "g" | "G" | "n" | "o" | "s" | "x" | "X" | "%"\n\nThe *fill* character can be any character other than \'{\' or \'}\'. The\npresence of a fill character is signaled by the character following\nit, which must be one of the alignment options. If the second\ncharacter of *format_spec* is not a valid alignment option, then it is\nassumed that both the fill character and the alignment option are\nabsent.\n\nThe meaning of the various alignment options is as follows:\n\n +-----------+------------------------------------------------------------+\n | Option | Meaning |\n +===========+============================================================+\n | ``\'<\'`` | Forces the field to be left-aligned within the available |\n | | space (this is the default for most objects). |\n +-----------+------------------------------------------------------------+\n | ``\'>\'`` | Forces the field to be right-aligned within the available |\n | | space (this is the default for numbers). |\n +-----------+------------------------------------------------------------+\n | ``\'=\'`` | Forces the padding to be placed after the sign (if any) |\n | | but before the digits. This is used for printing fields |\n | | in the form \'+000000120\'. This alignment option is only |\n | | valid for numeric types. |\n +-----------+------------------------------------------------------------+\n | ``\'^\'`` | Forces the field to be centered within the available |\n | | space. |\n +-----------+------------------------------------------------------------+\n\nNote that unless a minimum field width is defined, the field width\nwill always be the same size as the data to fill it, so that the\nalignment option has no meaning in this case.\n\nThe *sign* option is only valid for number types, and can be one of\nthe following:\n\n +-----------+------------------------------------------------------------+\n | Option | Meaning |\n +===========+============================================================+\n | ``\'+\'`` | indicates that a sign should be used for both positive as |\n | | well as negative numbers. |\n +-----------+------------------------------------------------------------+\n | ``\'-\'`` | indicates that a sign should be used only for negative |\n | | numbers (this is the default behavior). |\n +-----------+------------------------------------------------------------+\n | space | indicates that a leading space should be used on positive |\n | | numbers, and a minus sign on negative numbers. |\n +-----------+------------------------------------------------------------+\n\nThe ``\'#\'`` option is only valid for integers, and only for binary,\noctal, or hexadecimal output. If present, it specifies that the\noutput will be prefixed by ``\'0b\'``, ``\'0o\'``, or ``\'0x\'``,\nrespectively.\n\nThe ``\',\'`` option signals the use of a comma for a thousands\nseparator. For a locale aware separator, use the ``\'n\'`` integer\npresentation type instead.\n\nChanged in version 3.1: Added the ``\',\'`` option (see also **PEP\n378**).\n\n*width* is a decimal integer defining the minimum field width. If not\nspecified, then the field width will be determined by the content.\n\nIf the *width* field is preceded by a zero (``\'0\'``) character, this\nenables zero-padding. This is equivalent to an *alignment* type of\n``\'=\'`` and a *fill* character of ``\'0\'``.\n\nThe *precision* is a decimal number indicating how many digits should\nbe displayed after the decimal point for a floating point value\nformatted with ``\'f\'`` and ``\'F\'``, or before and after the decimal\npoint for a floating point value formatted with ``\'g\'`` or ``\'G\'``.\nFor non-number types the field indicates the maximum field size - in\nother words, how many characters will be used from the field content.\nThe *precision* is not allowed for integer values.\n\nFinally, the *type* determines how the data should be presented.\n\nThe available string presentation types are:\n\n +-----------+------------------------------------------------------------+\n | Type | Meaning |\n +===========+============================================================+\n | ``\'s\'`` | String format. This is the default type for strings and |\n | | may be omitted. |\n +-----------+------------------------------------------------------------+\n | None | The same as ``\'s\'``. |\n +-----------+------------------------------------------------------------+\n\nThe available integer presentation types are:\n\n +-----------+------------------------------------------------------------+\n | Type | Meaning |\n +===========+============================================================+\n | ``\'b\'`` | Binary format. Outputs the number in base 2. |\n +-----------+------------------------------------------------------------+\n | ``\'c\'`` | Character. Converts the integer to the corresponding |\n | | unicode character before printing. |\n +-----------+------------------------------------------------------------+\n | ``\'d\'`` | Decimal Integer. Outputs the number in base 10. |\n +-----------+------------------------------------------------------------+\n | ``\'o\'`` | Octal format. Outputs the number in base 8. |\n +-----------+------------------------------------------------------------+\n | ``\'x\'`` | Hex format. Outputs the number in base 16, using lower- |\n | | case letters for the digits above 9. |\n +-----------+------------------------------------------------------------+\n | ``\'X\'`` | Hex format. Outputs the number in base 16, using upper- |\n | | case letters for the digits above 9. |\n +-----------+------------------------------------------------------------+\n | ``\'n\'`` | Number. This is the same as ``\'d\'``, except that it uses |\n | | the current locale setting to insert the appropriate |\n | | number separator characters. |\n +-----------+------------------------------------------------------------+\n | None | The same as ``\'d\'``. |\n +-----------+------------------------------------------------------------+\n\nIn addition to the above presentation types, integers can be formatted\nwith the floating point presentation types listed below (except\n``\'n\'`` and None). When doing so, ``float()`` is used to convert the\ninteger to a floating point number before formatting.\n\nThe available presentation types for floating point and decimal values\nare:\n\n +-----------+------------------------------------------------------------+\n | Type | Meaning |\n +===========+============================================================+\n | ``\'e\'`` | Exponent notation. Prints the number in scientific |\n | | notation using the letter \'e\' to indicate the exponent. |\n +-----------+------------------------------------------------------------+\n | ``\'E\'`` | Exponent notation. Same as ``\'e\'`` except it uses an upper |\n | | case \'E\' as the separator character. |\n +-----------+------------------------------------------------------------+\n | ``\'f\'`` | Fixed point. Displays the number as a fixed-point number. |\n +-----------+------------------------------------------------------------+\n | ``\'F\'`` | Fixed point. Same as ``\'f\'``, but converts ``nan`` to |\n | | ``NAN`` and ``inf`` to ``INF``. |\n +-----------+------------------------------------------------------------+\n | ``\'g\'`` | General format. For a given precision ``p >= 1``, this |\n | | rounds the number to ``p`` significant digits and then |\n | | formats the result in either fixed-point format or in |\n | | scientific notation, depending on its magnitude. The |\n | | precise rules are as follows: suppose that the result |\n | | formatted with presentation type ``\'e\'`` and precision |\n | | ``p-1`` would have exponent ``exp``. Then if ``-4 <= exp |\n | | < p``, the number is formatted with presentation type |\n | | ``\'f\'`` and precision ``p-1-exp``. Otherwise, the number |\n | | is formatted with presentation type ``\'e\'`` and precision |\n | | ``p-1``. In both cases insignificant trailing zeros are |\n | | removed from the significand, and the decimal point is |\n | | also removed if there are no remaining digits following |\n | | it. Positive and negative infinity, positive and negative |\n | | zero, and nans, are formatted as ``inf``, ``-inf``, ``0``, |\n | | ``-0`` and ``nan`` respectively, regardless of the |\n | | precision. A precision of ``0`` is treated as equivalent |\n | | to a precision of ``1``. |\n +-----------+------------------------------------------------------------+\n | ``\'G\'`` | General format. Same as ``\'g\'`` except switches to ``\'E\'`` |\n | | if the number gets too large. The representations of |\n | | infinity and NaN are uppercased, too. |\n +-----------+------------------------------------------------------------+\n | ``\'n\'`` | Number. This is the same as ``\'g\'``, except that it uses |\n | | the current locale setting to insert the appropriate |\n | | number separator characters. |\n +-----------+------------------------------------------------------------+\n | ``\'%\'`` | Percentage. Multiplies the number by 100 and displays in |\n | | fixed (``\'f\'``) format, followed by a percent sign. |\n +-----------+------------------------------------------------------------+\n | None | Similar to ``\'g\'``, except with at least one digit past |\n | | the decimal point and a default precision of 12. This is |\n | | intended to match ``str()``, except you can add the other |\n | | format modifiers. |\n +-----------+------------------------------------------------------------+\n\n\nFormat examples\n===============\n\nThis section contains examples of the new format syntax and comparison\nwith the old ``%``-formatting.\n\nIn most of the cases the syntax is similar to the old\n``%``-formatting, with the addition of the ``{}`` and with ``:`` used\ninstead of ``%``. For example, ``\'%03.2f\'`` can be translated to\n``\'{:03.2f}\'``.\n\nThe new format syntax also supports new and different options, shown\nin the follow examples.\n\nAccessing arguments by position:\n\n >>> \'{0}, {1}, {2}\'.format(\'a\', \'b\', \'c\')\n \'a, b, c\'\n >>> \'{}, {}, {}\'.format(\'a\', \'b\', \'c\') # 3.1+ only\n \'a, b, c\'\n >>> \'{2}, {1}, {0}\'.format(\'a\', \'b\', \'c\')\n \'c, b, a\'\n >>> \'{2}, {1}, {0}\'.format(*\'abc\') # unpacking argument sequence\n \'c, b, a\'\n >>> \'{0}{1}{0}\'.format(\'abra\', \'cad\') # arguments\' indices can be repeated\n \'abracadabra\'\n\nAccessing arguments by name:\n\n >>> \'Coordinates: {latitude}, {longitude}\'.format(latitude=\'37.24N\', longitude=\'-115.81W\')\n \'Coordinates: 37.24N, -115.81W\'\n >>> coord = {\'latitude\': \'37.24N\', \'longitude\': \'-115.81W\'}\n >>> \'Coordinates: {latitude}, {longitude}\'.format(**coord)\n \'Coordinates: 37.24N, -115.81W\'\n\nAccessing arguments\' attributes:\n\n >>> c = 3-5j\n >>> (\'The complex number {0} is formed from the real part {0.real} \'\n ... \'and the imaginary part {0.imag}.\').format(c)\n \'The complex number (3-5j) is formed from the real part 3.0 and the imaginary part -5.0.\'\n >>> class Point:\n ... def __init__(self, x, y):\n ... self.x, self.y = x, y\n ... def __str__(self):\n ... return \'Point({self.x}, {self.y})\'.format(self=self)\n ...\n >>> str(Point(4, 2))\n \'Point(4, 2)\'\n\nAccessing arguments\' items:\n\n >>> coord = (3, 5)\n >>> \'X: {0[0]}; Y: {0[1]}\'.format(coord)\n \'X: 3; Y: 5\'\n\nReplacing ``%s`` and ``%r``:\n\n >>> "repr() shows quotes: {!r}; str() doesn\'t: {!s}".format(\'test1\', \'test2\')\n "repr() shows quotes: \'test1\'; str() doesn\'t: test2"\n\nAligning the text and specifying a width:\n\n >>> \'{:<30}\'.format(\'left aligned\')\n \'left aligned \'\n >>> \'{:>30}\'.format(\'right aligned\')\n \' right aligned\'\n >>> \'{:^30}\'.format(\'centered\')\n \' centered \'\n >>> \'{:*^30}\'.format(\'centered\') # use \'*\' as a fill char\n \'***********centered***********\'\n\nReplacing ``%+f``, ``%-f``, and ``% f`` and specifying a sign:\n\n >>> \'{:+f}; {:+f}\'.format(3.14, -3.14) # show it always\n \'+3.140000; -3.140000\'\n >>> \'{: f}; {: f}\'.format(3.14, -3.14) # show a space for positive numbers\n \' 3.140000; -3.140000\'\n >>> \'{:-f}; {:-f}\'.format(3.14, -3.14) # show only the minus -- same as \'{:f}; {:f}\'\n \'3.140000; -3.140000\'\n\nReplacing ``%x`` and ``%o`` and converting the value to different\nbases:\n\n >>> # format also supports binary numbers\n >>> "int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}".format(42)\n \'int: 42; hex: 2a; oct: 52; bin: 101010\'\n >>> # with 0x, 0o, or 0b as prefix:\n >>> "int: {0:d}; hex: {0:#x}; oct: {0:#o}; bin: {0:#b}".format(42)\n \'int: 42; hex: 0x2a; oct: 0o52; bin: 0b101010\'\n\nUsing the comma as a thousands separator:\n\n >>> \'{:,}\'.format(1234567890)\n \'1,234,567,890\'\n\nExpressing a percentage:\n\n >>> points = 19\n >>> total = 22\n >>> \'Correct answers: {:.2%}.\'.format(points/total)\n \'Correct answers: 86.36%\'\n\nUsing type-specific formatting:\n\n >>> import datetime\n >>> d = datetime.datetime(2010, 7, 4, 12, 15, 58)\n >>> \'{:%Y-%m-%d %H:%M:%S}\'.format(d)\n \'2010-07-04 12:15:58\'\n\nNesting arguments and more complex examples:\n\n >>> for align, text in zip(\'<^>\', [\'left\', \'center\', \'right\']):\n ... \'{0:{fill}{align}16}\'.format(text, fill=align, align=align)\n ...\n \'left<<<<<<<<<<<<\'\n \'^^^^^center^^^^^\'\n \'>>>>>>>>>>>right\'\n >>>\n >>> octets = [192, 168, 0, 1]\n >>> \'{:02X}{:02X}{:02X}{:02X}\'.format(*octets)\n \'C0A80001\'\n >>> int(_, 16)\n 3232235521\n >>>\n >>> width = 5\n >>> for num in range(5,12):\n ... for base in \'dXob\':\n ... print(\'{0:{width}{base}}\'.format(num, base=base, width=width), end=\' \')\n ... print()\n ...\n 5 5 5 101\n 6 6 6 110\n 7 7 7 111\n 8 8 10 1000\n 9 9 11 1001\n 10 A 12 1010\n 11 B 13 1011\n', 'function': '\nFunction definitions\n********************\n\nA function definition defines a user-defined function object (see\nsection *The standard type hierarchy*):\n\n funcdef ::= [decorators] "def" funcname "(" [parameter_list] ")" ["->" expression] ":" suite\n decorators ::= decorator+\n decorator ::= "@" dotted_name ["(" [argument_list [","]] ")"] NEWLINE\n dotted_name ::= identifier ("." identifier)*\n parameter_list ::= (defparameter ",")*\n ( "*" [parameter] ("," defparameter)*\n [, "**" parameter]\n | "**" parameter\n | defparameter [","] )\n parameter ::= identifier [":" expression]\n defparameter ::= parameter ["=" expression]\n funcname ::= identifier\n\nA function definition is an executable statement. Its execution binds\nthe function name in the current local namespace to a function object\n(a wrapper around the executable code for the function). This\nfunction object contains a reference to the current global namespace\nas the global namespace to be used when the function is called.\n\nThe function definition does not execute the function body; this gets\nexecuted only when the function is called. [3]\n\nA function definition may be wrapped by one or more *decorator*\nexpressions. Decorator expressions are evaluated when the function is\ndefined, in the scope that contains the function definition. The\nresult must be a callable, which is invoked with the function object\nas the only argument. The returned value is bound to the function name\ninstead of the function object. Multiple decorators are applied in\nnested fashion. For example, the following code\n\n @f1(arg)\n @f2\n def func(): pass\n\nis equivalent to\n\n def func(): pass\n func = f1(arg)(f2(func))\n\nWhen one or more parameters have the form *parameter* ``=``\n*expression*, the function is said to have "default parameter values."\nFor a parameter with a default value, the corresponding argument may\nbe omitted from a call, in which case the parameter\'s default value is\nsubstituted. If a parameter has a default value, all following\nparameters up until the "``*``" must also have a default value ---\nthis is a syntactic restriction that is not expressed by the grammar.\n\n**Default parameter values are evaluated when the function definition\nis executed.** This means that the expression is evaluated once, when\nthe function is defined, and that that same "pre-computed" value is\nused for each call. This is especially important to understand when a\ndefault parameter is a mutable object, such as a list or a dictionary:\nif the function modifies the object (e.g. by appending an item to a\nlist), the default value is in effect modified. This is generally not\nwhat was intended. A way around this is to use ``None`` as the\ndefault, and explicitly test for it in the body of the function, e.g.:\n\n def whats_on_the_telly(penguin=None):\n if penguin is None:\n penguin = []\n penguin.append("property of the zoo")\n return penguin\n\nFunction call semantics are described in more detail in section\n*Calls*. A function call always assigns values to all parameters\nmentioned in the parameter list, either from position arguments, from\nkeyword arguments, or from default values. If the form\n"``*identifier``" is present, it is initialized to a tuple receiving\nany excess positional parameters, defaulting to the empty tuple. If\nthe form "``**identifier``" is present, it is initialized to a new\ndictionary receiving any excess keyword arguments, defaulting to a new\nempty dictionary. Parameters after "``*``" or "``*identifier``" are\nkeyword-only parameters and may only be passed used keyword arguments.\n\nParameters may have annotations of the form "``: expression``"\nfollowing the parameter name. Any parameter may have an annotation\neven those of the form ``*identifier`` or ``**identifier``. Functions\nmay have "return" annotation of the form "``-> expression``" after the\nparameter list. These annotations can be any valid Python expression\nand are evaluated when the function definition is executed.\nAnnotations may be evaluated in a different order than they appear in\nthe source code. The presence of annotations does not change the\nsemantics of a function. The annotation values are available as\nvalues of a dictionary keyed by the parameters\' names in the\n``__annotations__`` attribute of the function object.\n\nIt is also possible to create anonymous functions (functions not bound\nto a name), for immediate use in expressions. This uses lambda forms,\ndescribed in section *Lambdas*. Note that the lambda form is merely a\nshorthand for a simplified function definition; a function defined in\na "``def``" statement can be passed around or assigned to another name\njust like a function defined by a lambda form. The "``def``" form is\nactually more powerful since it allows the execution of multiple\nstatements and annotations.\n\n**Programmer\'s note:** Functions are first-class objects. A "``def``"\nform executed inside a function definition defines a local function\nthat can be returned or passed around. Free variables used in the\nnested function can access the local variables of the function\ncontaining the def. See section *Naming and binding* for details.\n', - 'global': '\nThe ``global`` statement\n************************\n\n global_stmt ::= "global" identifier ("," identifier)*\n\nThe ``global`` statement is a declaration which holds for the entire\ncurrent code block. It means that the listed identifiers are to be\ninterpreted as globals. It would be impossible to assign to a global\nvariable without ``global``, although free variables may refer to\nglobals without being declared global.\n\nNames listed in a ``global`` statement must not be used in the same\ncode block textually preceding that ``global`` statement.\n\nNames listed in a ``global`` statement must not be defined as formal\nparameters or in a ``for`` loop control target, ``class`` definition,\nfunction definition, or ``import`` statement.\n\n(The current implementation does not enforce the latter two\nrestrictions, but programs should not abuse this freedom, as future\nimplementations may enforce them or silently change the meaning of the\nprogram.)\n\n**Programmer\'s note:** the ``global`` is a directive to the parser.\nIt applies only to code parsed at the same time as the ``global``\nstatement. In particular, a ``global`` statement contained in a string\nor code object supplied to the builtin ``exec()`` function does not\naffect the code block *containing* the function call, and code\ncontained in such a string is unaffected by ``global`` statements in\nthe code containing the function call. The same applies to the\n``eval()`` and ``compile()`` functions.\n', - 'id-classes': '\nReserved classes of identifiers\n*******************************\n\nCertain classes of identifiers (besides keywords) have special\nmeanings. These classes are identified by the patterns of leading and\ntrailing underscore characters:\n\n``_*``\n Not imported by ``from module import *``. The special identifier\n ``_`` is used in the interactive interpreter to store the result of\n the last evaluation; it is stored in the ``builtins`` module. When\n not in interactive mode, ``_`` has no special meaning and is not\n defined. See section *The import statement*.\n\n Note: The name ``_`` is often used in conjunction with\n internationalization; refer to the documentation for the\n ``gettext`` module for more information on this convention.\n\n``__*__``\n System-defined names. These names are defined by the interpreter\n and its implementation (including the standard library);\n applications should not expect to define additional names using\n this convention. The set of names of this class defined by Python\n may be extended in future versions. See section *Special method\n names*.\n\n``__*``\n Class-private names. Names in this category, when used within the\n context of a class definition, are re-written to use a mangled form\n to help avoid name clashes between "private" attributes of base and\n derived classes. See section *Identifiers (Names)*.\n', - 'identifiers': '\nIdentifiers and keywords\n************************\n\nIdentifiers (also referred to as *names*) are described by the\nfollowing lexical definitions.\n\nThe syntax of identifiers in Python is based on the Unicode standard\nannex UAX-31, with elaboration and changes as defined below; see also\n**PEP 3131** for further details.\n\nWithin the ASCII range (U+0001..U+007F), the valid characters for\nidentifiers are the same as in Python 2.x: the uppercase and lowercase\nletters ``A`` through ``Z``, the underscore ``_`` and, except for the\nfirst character, the digits ``0`` through ``9``.\n\nPython 3.0 introduces additional characters from outside the ASCII\nrange (see **PEP 3131**). For these characters, the classification\nuses the version of the Unicode Character Database as included in the\n``unicodedata`` module.\n\nIdentifiers are unlimited in length. Case is significant.\n\n identifier ::= id_start id_continue*\n id_start ::= \n id_continue ::= \n\nThe Unicode category codes mentioned above stand for:\n\n* *Lu* - uppercase letters\n\n* *Ll* - lowercase letters\n\n* *Lt* - titlecase letters\n\n* *Lm* - modifier letters\n\n* *Lo* - other letters\n\n* *Nl* - letter numbers\n\n* *Mn* - nonspacing marks\n\n* *Mc* - spacing combining marks\n\n* *Nd* - decimal numbers\n\n* *Pc* - connector punctuations\n\nAll identifiers are converted into the normal form NFC while parsing;\ncomparison of identifiers is based on NFC.\n\nA non-normative HTML file listing all valid identifier characters for\nUnicode 4.1 can be found at http://www.dcl.hpi.uni-\npotsdam.de/home/loewis/table-3131.html.\n\n\nKeywords\n========\n\nThe following identifiers are used as reserved words, or *keywords* of\nthe language, and cannot be used as ordinary identifiers. They must\nbe spelled exactly as written here:\n\n False class finally is return\n None continue for lambda try\n True def from nonlocal while\n and del global not with\n as elif if or yield\n assert else import pass\n break except in raise\n\n\nReserved classes of identifiers\n===============================\n\nCertain classes of identifiers (besides keywords) have special\nmeanings. These classes are identified by the patterns of leading and\ntrailing underscore characters:\n\n``_*``\n Not imported by ``from module import *``. The special identifier\n ``_`` is used in the interactive interpreter to store the result of\n the last evaluation; it is stored in the ``builtins`` module. When\n not in interactive mode, ``_`` has no special meaning and is not\n defined. See section *The import statement*.\n\n Note: The name ``_`` is often used in conjunction with\n internationalization; refer to the documentation for the\n ``gettext`` module for more information on this convention.\n\n``__*__``\n System-defined names. These names are defined by the interpreter\n and its implementation (including the standard library);\n applications should not expect to define additional names using\n this convention. The set of names of this class defined by Python\n may be extended in future versions. See section *Special method\n names*.\n\n``__*``\n Class-private names. Names in this category, when used within the\n context of a class definition, are re-written to use a mangled form\n to help avoid name clashes between "private" attributes of base and\n derived classes. See section *Identifiers (Names)*.\n', + 'global': '\nThe ``global`` statement\n************************\n\n global_stmt ::= "global" identifier ("," identifier)*\n\nThe ``global`` statement is a declaration which holds for the entire\ncurrent code block. It means that the listed identifiers are to be\ninterpreted as globals. It would be impossible to assign to a global\nvariable without ``global``, although free variables may refer to\nglobals without being declared global.\n\nNames listed in a ``global`` statement must not be used in the same\ncode block textually preceding that ``global`` statement.\n\nNames listed in a ``global`` statement must not be defined as formal\nparameters or in a ``for`` loop control target, ``class`` definition,\nfunction definition, or ``import`` statement.\n\n**CPython implementation detail:** The current implementation does not\nenforce the latter two restrictions, but programs should not abuse\nthis freedom, as future implementations may enforce them or silently\nchange the meaning of the program.\n\n**Programmer\'s note:** the ``global`` is a directive to the parser.\nIt applies only to code parsed at the same time as the ``global``\nstatement. In particular, a ``global`` statement contained in a string\nor code object supplied to the builtin ``exec()`` function does not\naffect the code block *containing* the function call, and code\ncontained in such a string is unaffected by ``global`` statements in\nthe code containing the function call. The same applies to the\n``eval()`` and ``compile()`` functions.\n', + 'id-classes': '\nReserved classes of identifiers\n*******************************\n\nCertain classes of identifiers (besides keywords) have special\nmeanings. These classes are identified by the patterns of leading and\ntrailing underscore characters:\n\n``_*``\n Not imported by ``from module import *``. The special identifier\n ``_`` is used in the interactive interpreter to store the result of\n the last evaluation; it is stored in the ``builtins`` module. When\n not in interactive mode, ``_`` has no special meaning and is not\n defined. See section *The import statement*.\n\n Note: The name ``_`` is often used in conjunction with\n internationalization; refer to the documentation for the\n ``gettext`` module for more information on this convention.\n\n``__*__``\n System-defined names. These names are defined by the interpreter\n and its implementation (including the standard library). Current\n system names are discussed in the *Special method names* section\n and elsewhere. More will likely be defined in future versions of\n Python. *Any* use of ``__*__`` names, in any context, that does\n not follow explicitly documented use, is subject to breakage\n without warning.\n\n``__*``\n Class-private names. Names in this category, when used within the\n context of a class definition, are re-written to use a mangled form\n to help avoid name clashes between "private" attributes of base and\n derived classes. See section *Identifiers (Names)*.\n', + 'identifiers': '\nIdentifiers and keywords\n************************\n\nIdentifiers (also referred to as *names*) are described by the\nfollowing lexical definitions.\n\nThe syntax of identifiers in Python is based on the Unicode standard\nannex UAX-31, with elaboration and changes as defined below; see also\n**PEP 3131** for further details.\n\nWithin the ASCII range (U+0001..U+007F), the valid characters for\nidentifiers are the same as in Python 2.x: the uppercase and lowercase\nletters ``A`` through ``Z``, the underscore ``_`` and, except for the\nfirst character, the digits ``0`` through ``9``.\n\nPython 3.0 introduces additional characters from outside the ASCII\nrange (see **PEP 3131**). For these characters, the classification\nuses the version of the Unicode Character Database as included in the\n``unicodedata`` module.\n\nIdentifiers are unlimited in length. Case is significant.\n\n identifier ::= xid_start xid_continue*\n id_start ::= \n id_continue ::= \n xid_start ::= \n xid_continue ::= \n\nThe Unicode category codes mentioned above stand for:\n\n* *Lu* - uppercase letters\n\n* *Ll* - lowercase letters\n\n* *Lt* - titlecase letters\n\n* *Lm* - modifier letters\n\n* *Lo* - other letters\n\n* *Nl* - letter numbers\n\n* *Mn* - nonspacing marks\n\n* *Mc* - spacing combining marks\n\n* *Nd* - decimal numbers\n\n* *Pc* - connector punctuations\n\n* *Other_ID_Start* - explicit list of characters in PropList.txt to\n support backwards compatibility\n\n* *Other_ID_Continue* - likewise\n\nAll identifiers are converted into the normal form NFKC while parsing;\ncomparison of identifiers is based on NFKC.\n\nA non-normative HTML file listing all valid identifier characters for\nUnicode 4.1 can be found at http://www.dcl.hpi.uni-\npotsdam.de/home/loewis/table-3131.html.\n\n\nKeywords\n========\n\nThe following identifiers are used as reserved words, or *keywords* of\nthe language, and cannot be used as ordinary identifiers. They must\nbe spelled exactly as written here:\n\n False class finally is return\n None continue for lambda try\n True def from nonlocal while\n and del global not with\n as elif if or yield\n assert else import pass\n break except in raise\n\n\nReserved classes of identifiers\n===============================\n\nCertain classes of identifiers (besides keywords) have special\nmeanings. These classes are identified by the patterns of leading and\ntrailing underscore characters:\n\n``_*``\n Not imported by ``from module import *``. The special identifier\n ``_`` is used in the interactive interpreter to store the result of\n the last evaluation; it is stored in the ``builtins`` module. When\n not in interactive mode, ``_`` has no special meaning and is not\n defined. See section *The import statement*.\n\n Note: The name ``_`` is often used in conjunction with\n internationalization; refer to the documentation for the\n ``gettext`` module for more information on this convention.\n\n``__*__``\n System-defined names. These names are defined by the interpreter\n and its implementation (including the standard library). Current\n system names are discussed in the *Special method names* section\n and elsewhere. More will likely be defined in future versions of\n Python. *Any* use of ``__*__`` names, in any context, that does\n not follow explicitly documented use, is subject to breakage\n without warning.\n\n``__*``\n Class-private names. Names in this category, when used within the\n context of a class definition, are re-written to use a mangled form\n to help avoid name clashes between "private" attributes of base and\n derived classes. See section *Identifiers (Names)*.\n', 'if': '\nThe ``if`` statement\n********************\n\nThe ``if`` statement is used for conditional execution:\n\n if_stmt ::= "if" expression ":" suite\n ( "elif" expression ":" suite )*\n ["else" ":" suite]\n\nIt selects exactly one of the suites by evaluating the expressions one\nby one until one is found to be true (see section *Boolean operations*\nfor the definition of true and false); then that suite is executed\n(and no other part of the ``if`` statement is executed or evaluated).\nIf all expressions are false, the suite of the ``else`` clause, if\npresent, is executed.\n', 'imaginary': '\nImaginary literals\n******************\n\nImaginary literals are described by the following lexical definitions:\n\n imagnumber ::= (floatnumber | intpart) ("j" | "J")\n\nAn imaginary literal yields a complex number with a real part of 0.0.\nComplex numbers are represented as a pair of floating point numbers\nand have the same restrictions on their range. To create a complex\nnumber with a nonzero real part, add a floating point number to it,\ne.g., ``(3+4j)``. Some examples of imaginary literals:\n\n 3.14j 10.j 10j .001j 1e100j 3.14e-10j\n', - 'import': '\nThe ``import`` statement\n************************\n\n import_stmt ::= "import" module ["as" name] ( "," module ["as" name] )*\n | "from" relative_module "import" identifier ["as" name]\n ( "," identifier ["as" name] )*\n | "from" relative_module "import" "(" identifier ["as" name]\n ( "," identifier ["as" name] )* [","] ")"\n | "from" module "import" "*"\n module ::= (identifier ".")* identifier\n relative_module ::= "."* module | "."+\n name ::= identifier\n\nImport statements are executed in two steps: (1) find a module, and\ninitialize it if necessary; (2) define a name or names in the local\nnamespace (of the scope where the ``import`` statement occurs). The\nstatement comes in two forms differing on whether it uses the ``from``\nkeyword. The first form (without ``from``) repeats these steps for\neach identifier in the list. The form with ``from`` performs step (1)\nonce, and then performs step (2) repeatedly. For a reference\nimplementation of step (1), see the ``importlib`` module.\n\nTo understand how step (1) occurs, one must first understand how\nPython handles hierarchical naming of modules. To help organize\nmodules and provide a hierarchy in naming, Python has a concept of\npackages. A package can contain other packages and modules while\nmodules cannot contain other modules or packages. From a file system\nperspective, packages are directories and modules are files. The\noriginal specification for packages is still available to read,\nalthough minor details have changed since the writing of that\ndocument.\n\nOnce the name of the module is known (unless otherwise specified, the\nterm "module" will refer to both packages and modules), searching for\nthe module or package can begin. The first place checked is\n``sys.modules``, the cache of all modules that have been imported\npreviously. If the module is found there then it is used in step (2)\nof import.\n\nIf the module is not found in the cache, then ``sys.meta_path`` is\nsearched (the specification for ``sys.meta_path`` can be found in\n**PEP 302**). The object is a list of *finder* objects which are\nqueried in order as to whether they know how to load the module by\ncalling their ``find_module()`` method with the name of the module. If\nthe module happens to be contained within a package (as denoted by the\nexistence of a dot in the name), then a second argument to\n``find_module()`` is given as the value of the ``__path__`` attribute\nfrom the parent package (everything up to the last dot in the name of\nthe module being imported). If a finder can find the module it returns\na *loader* (discussed later) or returns ``None``.\n\nIf none of the finders on ``sys.meta_path`` are able to find the\nmodule then some implicitly defined finders are queried.\nImplementations of Python vary in what implicit meta path finders are\ndefined. The one they all do define, though, is one that handles\n``sys.path_hooks``, ``sys.path_importer_cache``, and ``sys.path``.\n\nThe implicit finder searches for the requested module in the "paths"\nspecified in one of two places ("paths" do not have to be file system\npaths). If the module being imported is supposed to be contained\nwithin a package then the second argument passed to ``find_module()``,\n``__path__`` on the parent package, is used as the source of paths. If\nthe module is not contained in a package then ``sys.path`` is used as\nthe source of paths.\n\nOnce the source of paths is chosen it is iterated over to find a\nfinder that can handle that path. The dict at\n``sys.path_importer_cache`` caches finders for paths and is checked\nfor a finder. If the path does not have a finder cached then\n``sys.path_hooks`` is searched by calling each object in the list with\na single argument of the path, returning a finder or raises\n``ImportError``. If a finder is returned then it is cached in\n``sys.path_importer_cache`` and then used for that path entry. If no\nfinder can be found but the path exists then a value of ``None`` is\nstored in ``sys.path_importer_cache`` to signify that an implicit,\nfile-based finder that handles modules stored as individual files\nshould be used for that path. If the path does not exist then a finder\nwhich always returns ``None`` is placed in the cache for the path.\n\nIf no finder can find the module then ``ImportError`` is raised.\nOtherwise some finder returned a loader whose ``load_module()`` method\nis called with the name of the module to load (see **PEP 302** for the\noriginal definition of loaders). A loader has several responsibilities\nto perform on a module it loads. First, if the module already exists\nin ``sys.modules`` (a possibility if the loader is called outside of\nthe import machinery) then it is to use that module for initialization\nand not a new module. But if the module does not exist in\n``sys.modules`` then it is to be added to that dict before\ninitialization begins. If an error occurs during loading of the module\nand it was added to ``sys.modules`` it is to be removed from the dict.\nIf an error occurs but the module was already in ``sys.modules`` it is\nleft in the dict.\n\nThe loader must set several attributes on the module. ``__name__`` is\nto be set to the name of the module. ``__file__`` is to be the "path"\nto the file unless the module is built-in (and thus listed in\n``sys.builtin_module_names``) in which case the attribute is not set.\nIf what is being imported is a package then ``__path__`` is to be set\nto a list of paths to be searched when looking for modules and\npackages contained within the package being imported. ``__package__``\nis optional but should be set to the name of package that contains the\nmodule or package (the empty string is used for module not contained\nin a package). ``__loader__`` is also optional but should be set to\nthe loader object that is loading the module.\n\nIf an error occurs during loading then the loader raises\n``ImportError`` if some other exception is not already being\npropagated. Otherwise the loader returns the module that was loaded\nand initialized.\n\nWhen step (1) finishes without raising an exception, step (2) can\nbegin.\n\nThe first form of ``import`` statement binds the module name in the\nlocal namespace to the module object, and then goes on to import the\nnext identifier, if any. If the module name is followed by ``as``,\nthe name following ``as`` is used as the local name for the module.\n\nThe ``from`` form does not bind the module name: it goes through the\nlist of identifiers, looks each one of them up in the module found in\nstep (1), and binds the name in the local namespace to the object thus\nfound. As with the first form of ``import``, an alternate local name\ncan be supplied by specifying "``as`` localname". If a name is not\nfound, ``ImportError`` is raised. If the list of identifiers is\nreplaced by a star (``\'*\'``), all public names defined in the module\nare bound in the local namespace of the ``import`` statement..\n\nThe *public names* defined by a module are determined by checking the\nmodule\'s namespace for a variable named ``__all__``; if defined, it\nmust be a sequence of strings which are names defined or imported by\nthat module. The names given in ``__all__`` are all considered public\nand are required to exist. If ``__all__`` is not defined, the set of\npublic names includes all names found in the module\'s namespace which\ndo not begin with an underscore character (``\'_\'``). ``__all__``\nshould contain the entire public API. It is intended to avoid\naccidentally exporting items that are not part of the API (such as\nlibrary modules which were imported and used within the module).\n\nThe ``from`` form with ``*`` may only occur in a module scope. The\nwild card form of import --- ``import *`` --- is only allowed at the\nmodule level. Attempting to use it in class for function definitions\nwill raise a ``SyntaxError``.\n\nWhen specifying what module to import you do not have to specify the\nabsolute name of the module. When a module or package is contained\nwithin another package it is possible to make a relative import within\nthe same top package without having to mention the package name. By\nusing leading dots in the specified module or package after ``from``\nyou can specify how high to traverse up the current package hierarchy\nwithout specifying exact names. One leading dot means the current\npackage where the module making the import exists. Two dots means up\none package level. Three dots is up two levels, etc. So if you execute\n``from . import mod`` from a module in the ``pkg`` package then you\nwill end up importing ``pkg.mod``. If you execute ``from ..subpkg2\nimprt mod`` from within ``pkg.subpkg1`` you will import\n``pkg.subpkg2.mod``. The specification for relative imports is\ncontained within **PEP 328**.\n\n``importlib.import_module()`` is provided to support applications that\ndetermine which modules need to be loaded dynamically.\n\n\nFuture statements\n=================\n\nA *future statement* is a directive to the compiler that a particular\nmodule should be compiled using syntax or semantics that will be\navailable in a specified future release of Python. The future\nstatement is intended to ease migration to future versions of Python\nthat introduce incompatible changes to the language. It allows use of\nthe new features on a per-module basis before the release in which the\nfeature becomes standard.\n\n future_statement ::= "from" "__future__" "import" feature ["as" name]\n ("," feature ["as" name])*\n | "from" "__future__" "import" "(" feature ["as" name]\n ("," feature ["as" name])* [","] ")"\n feature ::= identifier\n name ::= identifier\n\nA future statement must appear near the top of the module. The only\nlines that can appear before a future statement are:\n\n* the module docstring (if any),\n\n* comments,\n\n* blank lines, and\n\n* other future statements.\n\nThe features recognized by Python 3.0 are ``absolute_import``,\n``division``, ``generators``, ``unicode_literals``,\n``print_function``, ``nested_scopes`` and ``with_statement``. They\nare all redundant because they are always enabled, and only kept for\nbackwards compatibility.\n\nA future statement is recognized and treated specially at compile\ntime: Changes to the semantics of core constructs are often\nimplemented by generating different code. It may even be the case\nthat a new feature introduces new incompatible syntax (such as a new\nreserved word), in which case the compiler may need to parse the\nmodule differently. Such decisions cannot be pushed off until\nruntime.\n\nFor any given release, the compiler knows which feature names have\nbeen defined, and raises a compile-time error if a future statement\ncontains a feature not known to it.\n\nThe direct runtime semantics are the same as for any import statement:\nthere is a standard module ``__future__``, described later, and it\nwill be imported in the usual way at the time the future statement is\nexecuted.\n\nThe interesting runtime semantics depend on the specific feature\nenabled by the future statement.\n\nNote that there is nothing special about the statement:\n\n import __future__ [as name]\n\nThat is not a future statement; it\'s an ordinary import statement with\nno special semantics or syntax restrictions.\n\nCode compiled by calls to the builtin functions ``exec()`` and\n``compile()`` that occur in a module ``M`` containing a future\nstatement will, by default, use the new syntax or semantics associated\nwith the future statement. This can be controlled by optional\narguments to ``compile()`` --- see the documentation of that function\nfor details.\n\nA future statement typed at an interactive interpreter prompt will\ntake effect for the rest of the interpreter session. If an\ninterpreter is started with the *-i* option, is passed a script name\nto execute, and the script includes a future statement, it will be in\neffect in the interactive session started after the script is\nexecuted.\n\nSee also:\n\n **PEP 236** - Back to the __future__\n The original proposal for the __future__ mechanism.\n', - 'in': '\nComparisons\n***********\n\nUnlike C, all comparison operations in Python have the same priority,\nwhich is lower than that of any arithmetic, shifting or bitwise\noperation. Also unlike C, expressions like ``a < b < c`` have the\ninterpretation that is conventional in mathematics:\n\n comparison ::= or_expr ( comp_operator or_expr )*\n comp_operator ::= "<" | ">" | "==" | ">=" | "<=" | "!="\n | "is" ["not"] | ["not"] "in"\n\nComparisons yield boolean values: ``True`` or ``False``.\n\nComparisons can be chained arbitrarily, e.g., ``x < y <= z`` is\nequivalent to ``x < y and y <= z``, except that ``y`` is evaluated\nonly once (but in both cases ``z`` is not evaluated at all when ``x <\ny`` is found to be false).\n\nFormally, if *a*, *b*, *c*, ..., *y*, *z* are expressions and *op1*,\n*op2*, ..., *opN* are comparison operators, then ``a op1 b op2 c ... y\nopN z`` is equivalent to ``a op1 b and b op2 c and ... y opN z``,\nexcept that each expression is evaluated at most once.\n\nNote that ``a op1 b op2 c`` doesn\'t imply any kind of comparison\nbetween *a* and *c*, so that, e.g., ``x < y > z`` is perfectly legal\n(though perhaps not pretty).\n\nThe operators ``<``, ``>``, ``==``, ``>=``, ``<=``, and ``!=`` compare\nthe values of two objects. The objects need not have the same type.\nIf both are numbers, they are converted to a common type. Otherwise,\nthe ``==`` and ``!=`` operators *always* consider objects of different\ntypes to be unequal, while the ``<``, ``>``, ``>=`` and ``<=``\noperators raise a ``TypeError`` when comparing objects of different\ntypes that do not implement these operators for the given pair of\ntypes. You can control comparison behavior of objects of non-builtin\ntypes by defining rich comparison methods like ``__gt__()``, described\nin section *Basic customization*.\n\nComparison of objects of the same type depends on the type:\n\n* Numbers are compared arithmetically.\n\n* The values ``float(\'NaN\')`` and ``Decimal(\'NaN\')`` are special. The\n are identical to themselves, ``x is x`` but are not equal to\n themselves, ``x != x``. Additionally, comparing any value to a\n not-a-number value will return ``False``. For example, both ``3 <\n float(\'NaN\')`` and ``float(\'NaN\') < 3`` will return ``False``.\n\n* Bytes objects are compared lexicographically using the numeric\n values of their elements.\n\n* Strings are compared lexicographically using the numeric equivalents\n (the result of the built-in function ``ord()``) of their characters.\n [3] String and bytes object can\'t be compared!\n\n* Tuples and lists are compared lexicographically using comparison of\n corresponding elements. This means that to compare equal, each\n element must compare equal and the two sequences must be of the same\n type and have the same length.\n\n If not equal, the sequences are ordered the same as their first\n differing elements. For example, ``[1,2,x] <= [1,2,y]`` has the\n same value as ``x <= y``. If the corresponding element does not\n exist, the shorter sequence is ordered first (for example, ``[1,2] <\n [1,2,3]``).\n\n* Mappings (dictionaries) compare equal if and only if their sorted\n ``(key, value)`` lists compare equal. [4] Outcomes other than\n equality are resolved consistently, but are not otherwise defined.\n [5]\n\n* Sets and frozensets define comparison operators to mean subset and\n superset tests. Those relations do not define total orderings (the\n two sets ``{1,2}`` and {2,3} are not equal, nor subsets of one\n another, nor supersets of one another). Accordingly, sets are not\n appropriate arguments for functions which depend on total ordering.\n For example, ``min()``, ``max()``, and ``sorted()`` produce\n undefined results given a list of sets as inputs.\n\n* Most other objects of builtin types compare unequal unless they are\n the same object; the choice whether one object is considered smaller\n or larger than another one is made arbitrarily but consistently\n within one execution of a program.\n\nComparison of objects of the differing types depends on whether either\nof the types provide explicit support for the comparison. Most\nnumeric types can be compared with one another, but comparisons of\n``float`` and ``Decimal`` are not supported to avoid the inevitable\nconfusion arising from representation issues such as ``float(\'1.1\')``\nbeing inexactly represented and therefore not exactly equal to\n``Decimal(\'1.1\')`` which is. When cross-type comparison is not\nsupported, the comparison method returns ``NotImplemented``. This can\ncreate the illusion of non-transitivity between supported cross-type\ncomparisons and unsupported comparisons. For example, ``Decimal(2) ==\n2`` and *2 == float(2)`* but ``Decimal(2) != float(2)``.\n\nThe operators ``in`` and ``not in`` test for membership. ``x in s``\nevaluates to true if *x* is a member of *s*, and false otherwise. ``x\nnot in s`` returns the negation of ``x in s``. All built-in sequences\nand set types support this as well as dictionary, for which ``in``\ntests whether a the dictionary has a given key. For container types\nsuch as list, tuple, set, frozenset, dict, or collections.deque, the\nexpression ``x in y`` is equivalent to ``any(x is e or x == e for val\ne in y)``.\n\nFor the string and bytes types, ``x in y`` is true if and only if *x*\nis a substring of *y*. An equivalent test is ``y.find(x) != -1``.\nEmpty strings are always considered to be a substring of any other\nstring, so ``"" in "abc"`` will return ``True``.\n\nFor user-defined classes which define the ``__contains__()`` method,\n``x in y`` is true if and only if ``y.__contains__(x)`` is true.\n\nFor user-defined classes which do not define ``__contains__()`` and do\ndefine ``__getitem__()``, ``x in y`` is true if and only if there is a\nnon-negative integer index *i* such that ``x == y[i]``, and all lower\ninteger indices do not raise ``IndexError`` exception. (If any other\nexception is raised, it is as if ``in`` raised that exception).\n\nThe operator ``not in`` is defined to have the inverse true value of\n``in``.\n\nThe operators ``is`` and ``is not`` test for object identity: ``x is\ny`` is true if and only if *x* and *y* are the same object. ``x is\nnot y`` yields the inverse truth value. [6]\n', + 'import': '\nThe ``import`` statement\n************************\n\n import_stmt ::= "import" module ["as" name] ( "," module ["as" name] )*\n | "from" relative_module "import" identifier ["as" name]\n ( "," identifier ["as" name] )*\n | "from" relative_module "import" "(" identifier ["as" name]\n ( "," identifier ["as" name] )* [","] ")"\n | "from" module "import" "*"\n module ::= (identifier ".")* identifier\n relative_module ::= "."* module | "."+\n name ::= identifier\n\nImport statements are executed in two steps: (1) find a module, and\ninitialize it if necessary; (2) define a name or names in the local\nnamespace (of the scope where the ``import`` statement occurs). The\nstatement comes in two forms differing on whether it uses the ``from``\nkeyword. The first form (without ``from``) repeats these steps for\neach identifier in the list. The form with ``from`` performs step (1)\nonce, and then performs step (2) repeatedly. For a reference\nimplementation of step (1), see the ``importlib`` module.\n\nTo understand how step (1) occurs, one must first understand how\nPython handles hierarchical naming of modules. To help organize\nmodules and provide a hierarchy in naming, Python has a concept of\npackages. A package can contain other packages and modules while\nmodules cannot contain other modules or packages. From a file system\nperspective, packages are directories and modules are files. The\noriginal specification for packages is still available to read,\nalthough minor details have changed since the writing of that\ndocument.\n\nOnce the name of the module is known (unless otherwise specified, the\nterm "module" will refer to both packages and modules), searching for\nthe module or package can begin. The first place checked is\n``sys.modules``, the cache of all modules that have been imported\npreviously. If the module is found there then it is used in step (2)\nof import.\n\nIf the module is not found in the cache, then ``sys.meta_path`` is\nsearched (the specification for ``sys.meta_path`` can be found in\n**PEP 302**). The object is a list of *finder* objects which are\nqueried in order as to whether they know how to load the module by\ncalling their ``find_module()`` method with the name of the module. If\nthe module happens to be contained within a package (as denoted by the\nexistence of a dot in the name), then a second argument to\n``find_module()`` is given as the value of the ``__path__`` attribute\nfrom the parent package (everything up to the last dot in the name of\nthe module being imported). If a finder can find the module it returns\na *loader* (discussed later) or returns ``None``.\n\nIf none of the finders on ``sys.meta_path`` are able to find the\nmodule then some implicitly defined finders are queried.\nImplementations of Python vary in what implicit meta path finders are\ndefined. The one they all do define, though, is one that handles\n``sys.path_hooks``, ``sys.path_importer_cache``, and ``sys.path``.\n\nThe implicit finder searches for the requested module in the "paths"\nspecified in one of two places ("paths" do not have to be file system\npaths). If the module being imported is supposed to be contained\nwithin a package then the second argument passed to ``find_module()``,\n``__path__`` on the parent package, is used as the source of paths. If\nthe module is not contained in a package then ``sys.path`` is used as\nthe source of paths.\n\nOnce the source of paths is chosen it is iterated over to find a\nfinder that can handle that path. The dict at\n``sys.path_importer_cache`` caches finders for paths and is checked\nfor a finder. If the path does not have a finder cached then\n``sys.path_hooks`` is searched by calling each object in the list with\na single argument of the path, returning a finder or raises\n``ImportError``. If a finder is returned then it is cached in\n``sys.path_importer_cache`` and then used for that path entry. If no\nfinder can be found but the path exists then a value of ``None`` is\nstored in ``sys.path_importer_cache`` to signify that an implicit,\nfile-based finder that handles modules stored as individual files\nshould be used for that path. If the path does not exist then a finder\nwhich always returns ``None`` is placed in the cache for the path.\n\nIf no finder can find the module then ``ImportError`` is raised.\nOtherwise some finder returned a loader whose ``load_module()`` method\nis called with the name of the module to load (see **PEP 302** for the\noriginal definition of loaders). A loader has several responsibilities\nto perform on a module it loads. First, if the module already exists\nin ``sys.modules`` (a possibility if the loader is called outside of\nthe import machinery) then it is to use that module for initialization\nand not a new module. But if the module does not exist in\n``sys.modules`` then it is to be added to that dict before\ninitialization begins. If an error occurs during loading of the module\nand it was added to ``sys.modules`` it is to be removed from the dict.\nIf an error occurs but the module was already in ``sys.modules`` it is\nleft in the dict.\n\nThe loader must set several attributes on the module. ``__name__`` is\nto be set to the name of the module. ``__file__`` is to be the "path"\nto the file unless the module is built-in (and thus listed in\n``sys.builtin_module_names``) in which case the attribute is not set.\nIf what is being imported is a package then ``__path__`` is to be set\nto a list of paths to be searched when looking for modules and\npackages contained within the package being imported. ``__package__``\nis optional but should be set to the name of package that contains the\nmodule or package (the empty string is used for module not contained\nin a package). ``__loader__`` is also optional but should be set to\nthe loader object that is loading the module.\n\nIf an error occurs during loading then the loader raises\n``ImportError`` if some other exception is not already being\npropagated. Otherwise the loader returns the module that was loaded\nand initialized.\n\nWhen step (1) finishes without raising an exception, step (2) can\nbegin.\n\nThe first form of ``import`` statement binds the module name in the\nlocal namespace to the module object, and then goes on to import the\nnext identifier, if any. If the module name is followed by ``as``,\nthe name following ``as`` is used as the local name for the module.\n\nThe ``from`` form does not bind the module name: it goes through the\nlist of identifiers, looks each one of them up in the module found in\nstep (1), and binds the name in the local namespace to the object thus\nfound. As with the first form of ``import``, an alternate local name\ncan be supplied by specifying "``as`` localname". If a name is not\nfound, ``ImportError`` is raised. If the list of identifiers is\nreplaced by a star (``\'*\'``), all public names defined in the module\nare bound in the local namespace of the ``import`` statement..\n\nThe *public names* defined by a module are determined by checking the\nmodule\'s namespace for a variable named ``__all__``; if defined, it\nmust be a sequence of strings which are names defined or imported by\nthat module. The names given in ``__all__`` are all considered public\nand are required to exist. If ``__all__`` is not defined, the set of\npublic names includes all names found in the module\'s namespace which\ndo not begin with an underscore character (``\'_\'``). ``__all__``\nshould contain the entire public API. It is intended to avoid\naccidentally exporting items that are not part of the API (such as\nlibrary modules which were imported and used within the module).\n\nThe ``from`` form with ``*`` may only occur in a module scope. The\nwild card form of import --- ``import *`` --- is only allowed at the\nmodule level. Attempting to use it in class or function definitions\nwill raise a ``SyntaxError``.\n\nWhen specifying what module to import you do not have to specify the\nabsolute name of the module. When a module or package is contained\nwithin another package it is possible to make a relative import within\nthe same top package without having to mention the package name. By\nusing leading dots in the specified module or package after ``from``\nyou can specify how high to traverse up the current package hierarchy\nwithout specifying exact names. One leading dot means the current\npackage where the module making the import exists. Two dots means up\none package level. Three dots is up two levels, etc. So if you execute\n``from . import mod`` from a module in the ``pkg`` package then you\nwill end up importing ``pkg.mod``. If you execute ``from ..subpkg2\nimprt mod`` from within ``pkg.subpkg1`` you will import\n``pkg.subpkg2.mod``. The specification for relative imports is\ncontained within **PEP 328**.\n\n``importlib.import_module()`` is provided to support applications that\ndetermine which modules need to be loaded dynamically.\n\n\nFuture statements\n=================\n\nA *future statement* is a directive to the compiler that a particular\nmodule should be compiled using syntax or semantics that will be\navailable in a specified future release of Python. The future\nstatement is intended to ease migration to future versions of Python\nthat introduce incompatible changes to the language. It allows use of\nthe new features on a per-module basis before the release in which the\nfeature becomes standard.\n\n future_statement ::= "from" "__future__" "import" feature ["as" name]\n ("," feature ["as" name])*\n | "from" "__future__" "import" "(" feature ["as" name]\n ("," feature ["as" name])* [","] ")"\n feature ::= identifier\n name ::= identifier\n\nA future statement must appear near the top of the module. The only\nlines that can appear before a future statement are:\n\n* the module docstring (if any),\n\n* comments,\n\n* blank lines, and\n\n* other future statements.\n\nThe features recognized by Python 3.0 are ``absolute_import``,\n``division``, ``generators``, ``unicode_literals``,\n``print_function``, ``nested_scopes`` and ``with_statement``. They\nare all redundant because they are always enabled, and only kept for\nbackwards compatibility.\n\nA future statement is recognized and treated specially at compile\ntime: Changes to the semantics of core constructs are often\nimplemented by generating different code. It may even be the case\nthat a new feature introduces new incompatible syntax (such as a new\nreserved word), in which case the compiler may need to parse the\nmodule differently. Such decisions cannot be pushed off until\nruntime.\n\nFor any given release, the compiler knows which feature names have\nbeen defined, and raises a compile-time error if a future statement\ncontains a feature not known to it.\n\nThe direct runtime semantics are the same as for any import statement:\nthere is a standard module ``__future__``, described later, and it\nwill be imported in the usual way at the time the future statement is\nexecuted.\n\nThe interesting runtime semantics depend on the specific feature\nenabled by the future statement.\n\nNote that there is nothing special about the statement:\n\n import __future__ [as name]\n\nThat is not a future statement; it\'s an ordinary import statement with\nno special semantics or syntax restrictions.\n\nCode compiled by calls to the built-in functions ``exec()`` and\n``compile()`` that occur in a module ``M`` containing a future\nstatement will, by default, use the new syntax or semantics associated\nwith the future statement. This can be controlled by optional\narguments to ``compile()`` --- see the documentation of that function\nfor details.\n\nA future statement typed at an interactive interpreter prompt will\ntake effect for the rest of the interpreter session. If an\ninterpreter is started with the *-i* option, is passed a script name\nto execute, and the script includes a future statement, it will be in\neffect in the interactive session started after the script is\nexecuted.\n\nSee also:\n\n **PEP 236** - Back to the __future__\n The original proposal for the __future__ mechanism.\n', + 'in': '\nComparisons\n***********\n\nUnlike C, all comparison operations in Python have the same priority,\nwhich is lower than that of any arithmetic, shifting or bitwise\noperation. Also unlike C, expressions like ``a < b < c`` have the\ninterpretation that is conventional in mathematics:\n\n comparison ::= or_expr ( comp_operator or_expr )*\n comp_operator ::= "<" | ">" | "==" | ">=" | "<=" | "!="\n | "is" ["not"] | ["not"] "in"\n\nComparisons yield boolean values: ``True`` or ``False``.\n\nComparisons can be chained arbitrarily, e.g., ``x < y <= z`` is\nequivalent to ``x < y and y <= z``, except that ``y`` is evaluated\nonly once (but in both cases ``z`` is not evaluated at all when ``x <\ny`` is found to be false).\n\nFormally, if *a*, *b*, *c*, ..., *y*, *z* are expressions and *op1*,\n*op2*, ..., *opN* are comparison operators, then ``a op1 b op2 c ... y\nopN z`` is equivalent to ``a op1 b and b op2 c and ... y opN z``,\nexcept that each expression is evaluated at most once.\n\nNote that ``a op1 b op2 c`` doesn\'t imply any kind of comparison\nbetween *a* and *c*, so that, e.g., ``x < y > z`` is perfectly legal\n(though perhaps not pretty).\n\nThe operators ``<``, ``>``, ``==``, ``>=``, ``<=``, and ``!=`` compare\nthe values of two objects. The objects need not have the same type.\nIf both are numbers, they are converted to a common type. Otherwise,\nthe ``==`` and ``!=`` operators *always* consider objects of different\ntypes to be unequal, while the ``<``, ``>``, ``>=`` and ``<=``\noperators raise a ``TypeError`` when comparing objects of different\ntypes that do not implement these operators for the given pair of\ntypes. You can control comparison behavior of objects of non-built-in\ntypes by defining rich comparison methods like ``__gt__()``, described\nin section *Basic customization*.\n\nComparison of objects of the same type depends on the type:\n\n* Numbers are compared arithmetically.\n\n* The values ``float(\'NaN\')`` and ``Decimal(\'NaN\')`` are special. The\n are identical to themselves, ``x is x`` but are not equal to\n themselves, ``x != x``. Additionally, comparing any value to a\n not-a-number value will return ``False``. For example, both ``3 <\n float(\'NaN\')`` and ``float(\'NaN\') < 3`` will return ``False``.\n\n* Bytes objects are compared lexicographically using the numeric\n values of their elements.\n\n* Strings are compared lexicographically using the numeric equivalents\n (the result of the built-in function ``ord()``) of their characters.\n [3] String and bytes object can\'t be compared!\n\n* Tuples and lists are compared lexicographically using comparison of\n corresponding elements. This means that to compare equal, each\n element must compare equal and the two sequences must be of the same\n type and have the same length.\n\n If not equal, the sequences are ordered the same as their first\n differing elements. For example, ``[1,2,x] <= [1,2,y]`` has the\n same value as ``x <= y``. If the corresponding element does not\n exist, the shorter sequence is ordered first (for example, ``[1,2] <\n [1,2,3]``).\n\n* Mappings (dictionaries) compare equal if and only if they have the\n same ``(key, value)`` pairs. Order comparisons ``(\'<\', \'<=\', \'>=\',\n \'>\')`` raise ``TypeError``.\n\n* Sets and frozensets define comparison operators to mean subset and\n superset tests. Those relations do not define total orderings (the\n two sets ``{1,2}`` and {2,3} are not equal, nor subsets of one\n another, nor supersets of one another). Accordingly, sets are not\n appropriate arguments for functions which depend on total ordering.\n For example, ``min()``, ``max()``, and ``sorted()`` produce\n undefined results given a list of sets as inputs.\n\n* Most other objects of built-in types compare unequal unless they are\n the same object; the choice whether one object is considered smaller\n or larger than another one is made arbitrarily but consistently\n within one execution of a program.\n\nComparison of objects of the differing types depends on whether either\nof the types provide explicit support for the comparison. Most\nnumeric types can be compared with one another, but comparisons of\n``float`` and ``Decimal`` are not supported to avoid the inevitable\nconfusion arising from representation issues such as ``float(\'1.1\')``\nbeing inexactly represented and therefore not exactly equal to\n``Decimal(\'1.1\')`` which is. When cross-type comparison is not\nsupported, the comparison method returns ``NotImplemented``. This can\ncreate the illusion of non-transitivity between supported cross-type\ncomparisons and unsupported comparisons. For example, ``Decimal(2) ==\n2`` and ``2 == float(2)`` but ``Decimal(2) != float(2)``.\n\nThe operators ``in`` and ``not in`` test for membership. ``x in s``\nevaluates to true if *x* is a member of *s*, and false otherwise. ``x\nnot in s`` returns the negation of ``x in s``. All built-in sequences\nand set types support this as well as dictionary, for which ``in``\ntests whether a the dictionary has a given key. For container types\nsuch as list, tuple, set, frozenset, dict, or collections.deque, the\nexpression ``x in y`` is equivalent to ``any(x is e or x == e for e in\ny)``.\n\nFor the string and bytes types, ``x in y`` is true if and only if *x*\nis a substring of *y*. An equivalent test is ``y.find(x) != -1``.\nEmpty strings are always considered to be a substring of any other\nstring, so ``"" in "abc"`` will return ``True``.\n\nFor user-defined classes which define the ``__contains__()`` method,\n``x in y`` is true if and only if ``y.__contains__(x)`` is true.\n\nFor user-defined classes which do not define ``__contains__()`` but do\ndefine ``__iter__()``, ``x in y`` is true if some value ``z`` with ``x\n== z`` is produced while iterating over ``y``. If an exception is\nraised during the iteration, it is as if ``in`` raised that exception.\n\nLastly, the old-style iteration protocol is tried: if a class defines\n``__getitem__()``, ``x in y`` is true if and only if there is a non-\nnegative integer index *i* such that ``x == y[i]``, and all lower\ninteger indices do not raise ``IndexError`` exception. (If any other\nexception is raised, it is as if ``in`` raised that exception).\n\nThe operator ``not in`` is defined to have the inverse true value of\n``in``.\n\nThe operators ``is`` and ``is not`` test for object identity: ``x is\ny`` is true if and only if *x* and *y* are the same object. ``x is\nnot y`` yields the inverse truth value. [4]\n', 'integers': '\nInteger literals\n****************\n\nInteger literals are described by the following lexical definitions:\n\n integer ::= decimalinteger | octinteger | hexinteger | bininteger\n decimalinteger ::= nonzerodigit digit* | "0"+\n nonzerodigit ::= "1"..."9"\n digit ::= "0"..."9"\n octinteger ::= "0" ("o" | "O") octdigit+\n hexinteger ::= "0" ("x" | "X") hexdigit+\n bininteger ::= "0" ("b" | "B") bindigit+\n octdigit ::= "0"..."7"\n hexdigit ::= digit | "a"..."f" | "A"..."F"\n bindigit ::= "0" | "1"\n\nThere is no limit for the length of integer literals apart from what\ncan be stored in available memory.\n\nNote that leading zeros in a non-zero decimal number are not allowed.\nThis is for disambiguation with C-style octal literals, which Python\nused before version 3.0.\n\nSome examples of integer literals:\n\n 7 2147483647 0o177 0b100110111\n 3 79228162514264337593543950336 0o377 0x100000000\n 79228162514264337593543950336 0xdeadbeef\n', 'lambda': '\nLambdas\n*******\n\n lambda_form ::= "lambda" [parameter_list]: expression\n lambda_form_nocond ::= "lambda" [parameter_list]: expression_nocond\n\nLambda forms (lambda expressions) have the same syntactic position as\nexpressions. They are a shorthand to create anonymous functions; the\nexpression ``lambda arguments: expression`` yields a function object.\nThe unnamed object behaves like a function object defined with\n\n def (arguments):\n return expression\n\nSee section *Function definitions* for the syntax of parameter lists.\nNote that functions created with lambda forms cannot contain\nstatements or annotations.\n', 'lists': '\nList displays\n*************\n\nA list display is a possibly empty series of expressions enclosed in\nsquare brackets:\n\n list_display ::= "[" [expression_list | comprehension] "]"\n\nA list display yields a new list object, the contents being specified\nby either a list of expressions or a comprehension. When a comma-\nseparated list of expressions is supplied, its elements are evaluated\nfrom left to right and placed into the list object in that order.\nWhen a comprehension is supplied, the list is constructed from the\nelements resulting from the comprehension.\n', - 'naming': "\nNaming and binding\n******************\n\n*Names* refer to objects. Names are introduced by name binding\noperations. Each occurrence of a name in the program text refers to\nthe *binding* of that name established in the innermost function block\ncontaining the use.\n\nA *block* is a piece of Python program text that is executed as a\nunit. The following are blocks: a module, a function body, and a class\ndefinition. Each command typed interactively is a block. A script\nfile (a file given as standard input to the interpreter or specified\non the interpreter command line the first argument) is a code block.\nA script command (a command specified on the interpreter command line\nwith the '**-c**' option) is a code block. The string argument passed\nto the built-in functions ``eval()`` and ``exec()`` is a code block.\n\nA code block is executed in an *execution frame*. A frame contains\nsome administrative information (used for debugging) and determines\nwhere and how execution continues after the code block's execution has\ncompleted.\n\nA *scope* defines the visibility of a name within a block. If a local\nvariable is defined in a block, its scope includes that block. If the\ndefinition occurs in a function block, the scope extends to any blocks\ncontained within the defining one, unless a contained block introduces\na different binding for the name. The scope of names defined in a\nclass block is limited to the class block; it does not extend to the\ncode blocks of methods -- this includes comprehensions and generator\nexpressions since they are implemented using a function scope. This\nmeans that the following will fail:\n\n class A:\n a = 42\n b = list(a + i for i in range(10))\n\nWhen a name is used in a code block, it is resolved using the nearest\nenclosing scope. The set of all such scopes visible to a code block\nis called the block's *environment*.\n\nIf a name is bound in a block, it is a local variable of that block,\nunless declared as ``nonlocal``. If a name is bound at the module\nlevel, it is a global variable. (The variables of the module code\nblock are local and global.) If a variable is used in a code block\nbut not defined there, it is a *free variable*.\n\nWhen a name is not found at all, a ``NameError`` exception is raised.\nIf the name refers to a local variable that has not been bound, a\n``UnboundLocalError`` exception is raised. ``UnboundLocalError`` is a\nsubclass of ``NameError``.\n\nThe following constructs bind names: formal parameters to functions,\n``import`` statements, class and function definitions (these bind the\nclass or function name in the defining block), and targets that are\nidentifiers if occurring in an assignment, ``for`` loop header, or\nafter ``as`` in a ``with`` statement or :keyword.`except` clause. The\n``import`` statement of the form ``from ... import *`` binds all names\ndefined in the imported module, except those beginning with an\nunderscore. This form may only be used at the module level.\n\nA target occurring in a ``del`` statement is also considered bound for\nthis purpose (though the actual semantics are to unbind the name). It\nis illegal to unbind a name that is referenced by an enclosing scope;\nthe compiler will report a ``SyntaxError``.\n\nEach assignment or import statement occurs within a block defined by a\nclass or function definition or at the module level (the top-level\ncode block).\n\nIf a name binding operation occurs anywhere within a code block, all\nuses of the name within the block are treated as references to the\ncurrent block. This can lead to errors when a name is used within a\nblock before it is bound. This rule is subtle. Python lacks\ndeclarations and allows name binding operations to occur anywhere\nwithin a code block. The local variables of a code block can be\ndetermined by scanning the entire text of the block for name binding\noperations.\n\nIf the ``global`` statement occurs within a block, all uses of the\nname specified in the statement refer to the binding of that name in\nthe top-level namespace. Names are resolved in the top-level\nnamespace by searching the global namespace, i.e. the namespace of the\nmodule containing the code block, and the builtin namespace, the\nnamespace of the module ``builtins``. The global namespace is\nsearched first. If the name is not found there, the builtin namespace\nis searched. The global statement must precede all uses of the name.\n\nThe built-in namespace associated with the execution of a code block\nis actually found by looking up the name ``__builtins__`` in its\nglobal namespace; this should be a dictionary or a module (in the\nlatter case the module's dictionary is used). By default, when in the\n``__main__`` module, ``__builtins__`` is the built-in module\n``builtins``; when in any other module, ``__builtins__`` is an alias\nfor the dictionary of the ``builtins`` module itself.\n``__builtins__`` can be set to a user-created dictionary to create a\nweak form of restricted execution.\n\nNote: Users should not touch ``__builtins__``; it is strictly an\n implementation detail. Users wanting to override values in the\n built-in namespace should ``import`` the ``builtins`` module and\n modify its attributes appropriately.\n\nThe namespace for a module is automatically created the first time a\nmodule is imported. The main module for a script is always called\n``__main__``.\n\nThe global statement has the same scope as a name binding operation in\nthe same block. If the nearest enclosing scope for a free variable\ncontains a global statement, the free variable is treated as a global.\n\nA class definition is an executable statement that may use and define\nnames. These references follow the normal rules for name resolution.\nThe namespace of the class definition becomes the attribute dictionary\nof the class. Names defined at the class scope are not visible in\nmethods.\n\n\nInteraction with dynamic features\n=================================\n\nThere are several cases where Python statements are illegal when used\nin conjunction with nested scopes that contain free variables.\n\nIf a variable is referenced in an enclosing scope, it is illegal to\ndelete the name. An error will be reported at compile time.\n\nIf the wild card form of import --- ``import *`` --- is used in a\nfunction and the function contains or is a nested block with free\nvariables, the compiler will raise a ``SyntaxError``.\n\nThe ``eval()`` and ``exec()`` functions do not have access to the full\nenvironment for resolving names. Names may be resolved in the local\nand global namespaces of the caller. Free variables are not resolved\nin the nearest enclosing namespace, but in the global namespace. [1]\nThe ``exec()`` and ``eval()`` functions have optional arguments to\noverride the global and local namespace. If only one namespace is\nspecified, it is used for both.\n", + 'naming': "\nNaming and binding\n******************\n\n*Names* refer to objects. Names are introduced by name binding\noperations. Each occurrence of a name in the program text refers to\nthe *binding* of that name established in the innermost function block\ncontaining the use.\n\nA *block* is a piece of Python program text that is executed as a\nunit. The following are blocks: a module, a function body, and a class\ndefinition. Each command typed interactively is a block. A script\nfile (a file given as standard input to the interpreter or specified\non the interpreter command line the first argument) is a code block.\nA script command (a command specified on the interpreter command line\nwith the '**-c**' option) is a code block. The string argument passed\nto the built-in functions ``eval()`` and ``exec()`` is a code block.\n\nA code block is executed in an *execution frame*. A frame contains\nsome administrative information (used for debugging) and determines\nwhere and how execution continues after the code block's execution has\ncompleted.\n\nA *scope* defines the visibility of a name within a block. If a local\nvariable is defined in a block, its scope includes that block. If the\ndefinition occurs in a function block, the scope extends to any blocks\ncontained within the defining one, unless a contained block introduces\na different binding for the name. The scope of names defined in a\nclass block is limited to the class block; it does not extend to the\ncode blocks of methods -- this includes comprehensions and generator\nexpressions since they are implemented using a function scope. This\nmeans that the following will fail:\n\n class A:\n a = 42\n b = list(a + i for i in range(10))\n\nWhen a name is used in a code block, it is resolved using the nearest\nenclosing scope. The set of all such scopes visible to a code block\nis called the block's *environment*.\n\nIf a name is bound in a block, it is a local variable of that block,\nunless declared as ``nonlocal``. If a name is bound at the module\nlevel, it is a global variable. (The variables of the module code\nblock are local and global.) If a variable is used in a code block\nbut not defined there, it is a *free variable*.\n\nWhen a name is not found at all, a ``NameError`` exception is raised.\nIf the name refers to a local variable that has not been bound, a\n``UnboundLocalError`` exception is raised. ``UnboundLocalError`` is a\nsubclass of ``NameError``.\n\nThe following constructs bind names: formal parameters to functions,\n``import`` statements, class and function definitions (these bind the\nclass or function name in the defining block), and targets that are\nidentifiers if occurring in an assignment, ``for`` loop header, or\nafter ``as`` in a ``with`` statement or ``except`` clause. The\n``import`` statement of the form ``from ... import *`` binds all names\ndefined in the imported module, except those beginning with an\nunderscore. This form may only be used at the module level.\n\nA target occurring in a ``del`` statement is also considered bound for\nthis purpose (though the actual semantics are to unbind the name). It\nis illegal to unbind a name that is referenced by an enclosing scope;\nthe compiler will report a ``SyntaxError``.\n\nEach assignment or import statement occurs within a block defined by a\nclass or function definition or at the module level (the top-level\ncode block).\n\nIf a name binding operation occurs anywhere within a code block, all\nuses of the name within the block are treated as references to the\ncurrent block. This can lead to errors when a name is used within a\nblock before it is bound. This rule is subtle. Python lacks\ndeclarations and allows name binding operations to occur anywhere\nwithin a code block. The local variables of a code block can be\ndetermined by scanning the entire text of the block for name binding\noperations.\n\nIf the ``global`` statement occurs within a block, all uses of the\nname specified in the statement refer to the binding of that name in\nthe top-level namespace. Names are resolved in the top-level\nnamespace by searching the global namespace, i.e. the namespace of the\nmodule containing the code block, and the builtins namespace, the\nnamespace of the module ``builtins``. The global namespace is\nsearched first. If the name is not found there, the builtins\nnamespace is searched. The global statement must precede all uses of\nthe name.\n\nThe builtins namespace associated with the execution of a code block\nis actually found by looking up the name ``__builtins__`` in its\nglobal namespace; this should be a dictionary or a module (in the\nlatter case the module's dictionary is used). By default, when in the\n``__main__`` module, ``__builtins__`` is the built-in module\n``builtins``; when in any other module, ``__builtins__`` is an alias\nfor the dictionary of the ``builtins`` module itself.\n``__builtins__`` can be set to a user-created dictionary to create a\nweak form of restricted execution.\n\n**CPython implementation detail:** Users should not touch\n``__builtins__``; it is strictly an implementation detail. Users\nwanting to override values in the builtins namespace should ``import``\nthe ``builtins`` module and modify its attributes appropriately.\n\nThe namespace for a module is automatically created the first time a\nmodule is imported. The main module for a script is always called\n``__main__``.\n\nThe ``global`` statement has the same scope as a name binding\noperation in the same block. If the nearest enclosing scope for a\nfree variable contains a global statement, the free variable is\ntreated as a global.\n\nA class definition is an executable statement that may use and define\nnames. These references follow the normal rules for name resolution.\nThe namespace of the class definition becomes the attribute dictionary\nof the class. Names defined at the class scope are not visible in\nmethods.\n\n\nInteraction with dynamic features\n=================================\n\nThere are several cases where Python statements are illegal when used\nin conjunction with nested scopes that contain free variables.\n\nIf a variable is referenced in an enclosing scope, it is illegal to\ndelete the name. An error will be reported at compile time.\n\nIf the wild card form of import --- ``import *`` --- is used in a\nfunction and the function contains or is a nested block with free\nvariables, the compiler will raise a ``SyntaxError``.\n\nThe ``eval()`` and ``exec()`` functions do not have access to the full\nenvironment for resolving names. Names may be resolved in the local\nand global namespaces of the caller. Free variables are not resolved\nin the nearest enclosing namespace, but in the global namespace. [1]\nThe ``exec()`` and ``eval()`` functions have optional arguments to\noverride the global and local namespace. If only one namespace is\nspecified, it is used for both.\n", + 'nonlocal': '\nThe ``nonlocal`` statement\n**************************\n\n nonlocal_stmt ::= "nonlocal" identifier ("," identifier)*\n\nThe ``nonlocal`` statement causes the listed identifiers to refer to\npreviously bound variables in the nearest enclosing scope. This is\nimportant because the default behavior for binding is to search the\nlocal namespace first. The statement allows encapsulated code to\nrebind variables outside of the local scope besides the global\n(module) scope.\n\nNames listed in a ``nonlocal`` statement, unlike to those listed in a\n``global`` statement, must refer to pre-existing bindings in an\nenclosing scope (the scope in which a new binding should be created\ncannot be determined unambiguously).\n\nNames listed in a ``nonlocal`` statement must not collide with pre-\nexisting bindings in the local scope.\n\nSee also:\n\n **PEP 3104** - Access to Names in Outer Scopes\n The specification for the ``nonlocal`` statement.\n', 'numbers': "\nNumeric literals\n****************\n\nThere are three types of numeric literals: integers, floating point\nnumbers, and imaginary numbers. There are no complex literals\n(complex numbers can be formed by adding a real number and an\nimaginary number).\n\nNote that numeric literals do not include a sign; a phrase like ``-1``\nis actually an expression composed of the unary operator '``-``' and\nthe literal ``1``.\n", - 'numeric-types': "\nEmulating numeric types\n***********************\n\nThe following methods can be defined to emulate numeric objects.\nMethods corresponding to operations that are not supported by the\nparticular kind of number implemented (e.g., bitwise operations for\nnon-integral numbers) should be left undefined.\n\nobject.__add__(self, other)\nobject.__sub__(self, other)\nobject.__mul__(self, other)\nobject.__truediv__(self, other)\nobject.__floordiv__(self, other)\nobject.__mod__(self, other)\nobject.__divmod__(self, other)\nobject.__pow__(self, other[, modulo])\nobject.__lshift__(self, other)\nobject.__rshift__(self, other)\nobject.__and__(self, other)\nobject.__xor__(self, other)\nobject.__or__(self, other)\n\n These methods are called to implement the binary arithmetic\n operations (``+``, ``-``, ``*``, ``/``, ``//``, ``%``,\n ``divmod()``, ``pow()``, ``**``, ``<<``, ``>>``, ``&``, ``^``,\n ``|``). For instance, to evaluate the expression ``x + y``, where\n *x* is an instance of a class that has an ``__add__()`` method,\n ``x.__add__(y)`` is called. The ``__divmod__()`` method should be\n the equivalent to using ``__floordiv__()`` and ``__mod__()``; it\n should not be related to ``__truediv__()``. Note that\n ``__pow__()`` should be defined to accept an optional third\n argument if the ternary version of the built-in ``pow()`` function\n is to be supported.\n\n If one of those methods does not support the operation with the\n supplied arguments, it should return ``NotImplemented``.\n\nobject.__radd__(self, other)\nobject.__rsub__(self, other)\nobject.__rmul__(self, other)\nobject.__rtruediv__(self, other)\nobject.__rfloordiv__(self, other)\nobject.__rmod__(self, other)\nobject.__rdivmod__(self, other)\nobject.__rpow__(self, other)\nobject.__rlshift__(self, other)\nobject.__rrshift__(self, other)\nobject.__rand__(self, other)\nobject.__rxor__(self, other)\nobject.__ror__(self, other)\n\n These methods are called to implement the binary arithmetic\n operations (``+``, ``-``, ``*``, ``/``, ``//``, ``%``,\n ``divmod()``, ``pow()``, ``**``, ``<<``, ``>>``, ``&``, ``^``,\n ``|``) with reflected (swapped) operands. These functions are only\n called if the left operand does not support the corresponding\n operation and the operands are of different types. [3] For\n instance, to evaluate the expression ``x - y``, where *y* is an\n instance of a class that has an ``__rsub__()`` method,\n ``y.__rsub__(x)`` is called if ``x.__sub__(y)`` returns\n *NotImplemented*.\n\n Note that ternary ``pow()`` will not try calling ``__rpow__()``\n (the coercion rules would become too complicated).\n\n Note: If the right operand's type is a subclass of the left operand's\n type and that subclass provides the reflected method for the\n operation, this method will be called before the left operand's\n non-reflected method. This behavior allows subclasses to\n override their ancestors' operations.\n\nobject.__iadd__(self, other)\nobject.__isub__(self, other)\nobject.__imul__(self, other)\nobject.__itruediv__(self, other)\nobject.__ifloordiv__(self, other)\nobject.__imod__(self, other)\nobject.__ipow__(self, other[, modulo])\nobject.__ilshift__(self, other)\nobject.__irshift__(self, other)\nobject.__iand__(self, other)\nobject.__ixor__(self, other)\nobject.__ior__(self, other)\n\n These methods are called to implement the augmented arithmetic\n assignments (``+=``, ``-=``, ``*=``, ``/=``, ``//=``, ``%=``,\n ``**=``, ``<<=``, ``>>=``, ``&=``, ``^=``, ``|=``). These methods\n should attempt to do the operation in-place (modifying *self*) and\n return the result (which could be, but does not have to be,\n *self*). If a specific method is not defined, the augmented\n assignment falls back to the normal methods. For instance, to\n execute the statement ``x += y``, where *x* is an instance of a\n class that has an ``__iadd__()`` method, ``x.__iadd__(y)`` is\n called. If *x* is an instance of a class that does not define a\n ``__iadd__()`` method, ``x.__add__(y)`` and ``y.__radd__(x)`` are\n considered, as with the evaluation of ``x + y``.\n\nobject.__neg__(self)\nobject.__pos__(self)\nobject.__abs__(self)\nobject.__invert__(self)\n\n Called to implement the unary arithmetic operations (``-``, ``+``,\n ``abs()`` and ``~``).\n\nobject.__complex__(self)\nobject.__int__(self)\nobject.__float__(self)\nobject.__round__(self[, n])\n\n Called to implement the built-in functions ``complex()``,\n ``int()``, ``float()`` and ``round()``. Should return a value of\n the appropriate type.\n\nobject.__index__(self)\n\n Called to implement ``operator.index()``. Also called whenever\n Python needs an integer object (such as in slicing, or in the\n built-in ``bin()``, ``hex()`` and ``oct()`` functions). Must return\n an integer.\n", - 'objects': '\nObjects, values and types\n*************************\n\n*Objects* are Python\'s abstraction for data. All data in a Python\nprogram is represented by objects or by relations between objects. (In\na sense, and in conformance to Von Neumann\'s model of a "stored\nprogram computer," code is also represented by objects.)\n\nEvery object has an identity, a type and a value. An object\'s\n*identity* never changes once it has been created; you may think of it\nas the object\'s address in memory. The \'``is``\' operator compares the\nidentity of two objects; the ``id()`` function returns an integer\nrepresenting its identity (currently implemented as its address). An\nobject\'s *type* is also unchangeable. [1] An object\'s type determines\nthe operations that the object supports (e.g., "does it have a\nlength?") and also defines the possible values for objects of that\ntype. The ``type()`` function returns an object\'s type (which is an\nobject itself). The *value* of some objects can change. Objects\nwhose value can change are said to be *mutable*; objects whose value\nis unchangeable once they are created are called *immutable*. (The\nvalue of an immutable container object that contains a reference to a\nmutable object can change when the latter\'s value is changed; however\nthe container is still considered immutable, because the collection of\nobjects it contains cannot be changed. So, immutability is not\nstrictly the same as having an unchangeable value, it is more subtle.)\nAn object\'s mutability is determined by its type; for instance,\nnumbers, strings and tuples are immutable, while dictionaries and\nlists are mutable.\n\nObjects are never explicitly destroyed; however, when they become\nunreachable they may be garbage-collected. An implementation is\nallowed to postpone garbage collection or omit it altogether --- it is\na matter of implementation quality how garbage collection is\nimplemented, as long as no objects are collected that are still\nreachable. (Implementation note: CPython currently uses a reference-\ncounting scheme with (optional) delayed detection of cyclically linked\ngarbage, which collects most objects as soon as they become\nunreachable, but is not guaranteed to collect garbage containing\ncircular references. See the documentation of the ``gc`` module for\ninformation on controlling the collection of cyclic garbage. Other\nimplementations act differently and CPython may change.)\n\nNote that the use of the implementation\'s tracing or debugging\nfacilities may keep objects alive that would normally be collectable.\nAlso note that catching an exception with a \'``try``...``except``\'\nstatement may keep objects alive.\n\nSome objects contain references to "external" resources such as open\nfiles or windows. It is understood that these resources are freed\nwhen the object is garbage-collected, but since garbage collection is\nnot guaranteed to happen, such objects also provide an explicit way to\nrelease the external resource, usually a ``close()`` method. Programs\nare strongly recommended to explicitly close such objects. The\n\'``try``...``finally``\' statement and the \'``with``\' statement provide\nconvenient ways to do this.\n\nSome objects contain references to other objects; these are called\n*containers*. Examples of containers are tuples, lists and\ndictionaries. The references are part of a container\'s value. In\nmost cases, when we talk about the value of a container, we imply the\nvalues, not the identities of the contained objects; however, when we\ntalk about the mutability of a container, only the identities of the\nimmediately contained objects are implied. So, if an immutable\ncontainer (like a tuple) contains a reference to a mutable object, its\nvalue changes if that mutable object is changed.\n\nTypes affect almost all aspects of object behavior. Even the\nimportance of object identity is affected in some sense: for immutable\ntypes, operations that compute new values may actually return a\nreference to any existing object with the same type and value, while\nfor mutable objects this is not allowed. E.g., after ``a = 1; b =\n1``, ``a`` and ``b`` may or may not refer to the same object with the\nvalue one, depending on the implementation, but after ``c = []; d =\n[]``, ``c`` and ``d`` are guaranteed to refer to two different,\nunique, newly created empty lists. (Note that ``c = d = []`` assigns\nthe same object to both ``c`` and ``d``.)\n', - 'operator-summary': '\nSummary\n*******\n\nThe following table summarizes the operator precedences in Python,\nfrom lowest precedence (least binding) to highest precedence (most\nbinding). Operators in the same box have the same precedence. Unless\nthe syntax is explicitly given, operators are binary. Operators in\nthe same box group left to right (except for comparisons, including\ntests, which all have the same precedence and chain from left to right\n--- see section *Comparisons* --- and exponentiation, which groups\nfrom right to left).\n\n+-------------------------------------------------+---------------------------------------+\n| Operator | Description |\n+=================================================+=======================================+\n| ``lambda`` | Lambda expression |\n+-------------------------------------------------+---------------------------------------+\n| ``or`` | Boolean OR |\n+-------------------------------------------------+---------------------------------------+\n| ``and`` | Boolean AND |\n+-------------------------------------------------+---------------------------------------+\n| ``not`` *x* | Boolean NOT |\n+-------------------------------------------------+---------------------------------------+\n| ``in``, ``not`` ``in``, ``is``, ``is not``, | Comparisons, including membership |\n| ``<``, ``<=``, ``>``, ``>=``, ``!=``, ``==`` | tests and identity tests, |\n+-------------------------------------------------+---------------------------------------+\n| ``|`` | Bitwise OR |\n+-------------------------------------------------+---------------------------------------+\n| ``^`` | Bitwise XOR |\n+-------------------------------------------------+---------------------------------------+\n| ``&`` | Bitwise AND |\n+-------------------------------------------------+---------------------------------------+\n| ``<<``, ``>>`` | Shifts |\n+-------------------------------------------------+---------------------------------------+\n| ``+``, ``-`` | Addition and subtraction |\n+-------------------------------------------------+---------------------------------------+\n| ``*``, ``/``, ``//``, ``%`` | Multiplication, division, remainder |\n+-------------------------------------------------+---------------------------------------+\n| ``+x``, ``-x``, ``~x`` | Positive, negative, bitwise NOT |\n+-------------------------------------------------+---------------------------------------+\n| ``**`` | Exponentiation [7] |\n+-------------------------------------------------+---------------------------------------+\n| ``x[index]``, ``x[index:index]``, | Subscription, slicing, call, |\n| ``x(arguments...)``, ``x.attribute`` | attribute reference |\n+-------------------------------------------------+---------------------------------------+\n| ``(expressions...)``, ``[expressions...]``, | Binding or tuple display, list |\n| ``{key:datum...}``, | display, dictionary display, |\n+-------------------------------------------------+---------------------------------------+\n\n-[ Footnotes ]-\n\n[1] While ``abs(x%y) < abs(y)`` is true mathematically, for floats it\n may not be true numerically due to roundoff. For example, and\n assuming a platform on which a Python float is an IEEE 754 double-\n precision number, in order that ``-1e-100 % 1e100`` have the same\n sign as ``1e100``, the computed result is ``-1e-100 + 1e100``,\n which is numerically exactly equal to ``1e100``. Function\n ``fmod()`` in the ``math`` module returns a result whose sign\n matches the sign of the first argument instead, and so returns\n ``-1e-100`` in this case. Which approach is more appropriate\n depends on the application.\n\n[2] If x is very close to an exact integer multiple of y, it\'s\n possible for ``x//y`` to be one larger than ``(x-x%y)//y`` due to\n rounding. In such cases, Python returns the latter result, in\n order to preserve that ``divmod(x,y)[0] * y + x % y`` be very\n close to ``x``.\n\n[3] While comparisons between strings make sense at the byte level,\n they may be counter-intuitive to users. For example, the strings\n ``"\\u00C7"`` and ``"\\u0327\\u0043"`` compare differently, even\n though they both represent the same unicode character (LATIN\n CAPITAL LETTER C WITH CEDILLA). To compare strings in a human\n recognizable way, compare using ``unicodedata.normalize()``.\n\n[4] The implementation computes this efficiently, without constructing\n lists or sorting.\n\n[5] Earlier versions of Python used lexicographic comparison of the\n sorted (key, value) lists, but this was very expensive for the\n common case of comparing for equality. An even earlier version of\n Python compared dictionaries by identity only, but this caused\n surprises because people expected to be able to test a dictionary\n for emptiness by comparing it to ``{}``.\n\n[6] Due to automatic garbage-collection, free lists, and the dynamic\n nature of descriptors, you may notice seemingly unusual behaviour\n in certain uses of the ``is`` operator, like those involving\n comparisons between instance methods, or constants. Check their\n documentation for more info.\n\n[7] The power operator ``**`` binds less tightly than an arithmetic or\n bitwise unary operator on its right, that is, ``2**-1`` is\n ``0.5``.\n', + 'numeric-types': "\nEmulating numeric types\n***********************\n\nThe following methods can be defined to emulate numeric objects.\nMethods corresponding to operations that are not supported by the\nparticular kind of number implemented (e.g., bitwise operations for\nnon-integral numbers) should be left undefined.\n\nobject.__add__(self, other)\nobject.__sub__(self, other)\nobject.__mul__(self, other)\nobject.__truediv__(self, other)\nobject.__floordiv__(self, other)\nobject.__mod__(self, other)\nobject.__divmod__(self, other)\nobject.__pow__(self, other[, modulo])\nobject.__lshift__(self, other)\nobject.__rshift__(self, other)\nobject.__and__(self, other)\nobject.__xor__(self, other)\nobject.__or__(self, other)\n\n These methods are called to implement the binary arithmetic\n operations (``+``, ``-``, ``*``, ``/``, ``//``, ``%``,\n ``divmod()``, ``pow()``, ``**``, ``<<``, ``>>``, ``&``, ``^``,\n ``|``). For instance, to evaluate the expression ``x + y``, where\n *x* is an instance of a class that has an ``__add__()`` method,\n ``x.__add__(y)`` is called. The ``__divmod__()`` method should be\n the equivalent to using ``__floordiv__()`` and ``__mod__()``; it\n should not be related to ``__truediv__()``. Note that\n ``__pow__()`` should be defined to accept an optional third\n argument if the ternary version of the built-in ``pow()`` function\n is to be supported.\n\n If one of those methods does not support the operation with the\n supplied arguments, it should return ``NotImplemented``.\n\nobject.__radd__(self, other)\nobject.__rsub__(self, other)\nobject.__rmul__(self, other)\nobject.__rtruediv__(self, other)\nobject.__rfloordiv__(self, other)\nobject.__rmod__(self, other)\nobject.__rdivmod__(self, other)\nobject.__rpow__(self, other)\nobject.__rlshift__(self, other)\nobject.__rrshift__(self, other)\nobject.__rand__(self, other)\nobject.__rxor__(self, other)\nobject.__ror__(self, other)\n\n These methods are called to implement the binary arithmetic\n operations (``+``, ``-``, ``*``, ``/``, ``//``, ``%``,\n ``divmod()``, ``pow()``, ``**``, ``<<``, ``>>``, ``&``, ``^``,\n ``|``) with reflected (swapped) operands. These functions are only\n called if the left operand does not support the corresponding\n operation and the operands are of different types. [2] For\n instance, to evaluate the expression ``x - y``, where *y* is an\n instance of a class that has an ``__rsub__()`` method,\n ``y.__rsub__(x)`` is called if ``x.__sub__(y)`` returns\n *NotImplemented*.\n\n Note that ternary ``pow()`` will not try calling ``__rpow__()``\n (the coercion rules would become too complicated).\n\n Note: If the right operand's type is a subclass of the left operand's\n type and that subclass provides the reflected method for the\n operation, this method will be called before the left operand's\n non-reflected method. This behavior allows subclasses to\n override their ancestors' operations.\n\nobject.__iadd__(self, other)\nobject.__isub__(self, other)\nobject.__imul__(self, other)\nobject.__itruediv__(self, other)\nobject.__ifloordiv__(self, other)\nobject.__imod__(self, other)\nobject.__ipow__(self, other[, modulo])\nobject.__ilshift__(self, other)\nobject.__irshift__(self, other)\nobject.__iand__(self, other)\nobject.__ixor__(self, other)\nobject.__ior__(self, other)\n\n These methods are called to implement the augmented arithmetic\n assignments (``+=``, ``-=``, ``*=``, ``/=``, ``//=``, ``%=``,\n ``**=``, ``<<=``, ``>>=``, ``&=``, ``^=``, ``|=``). These methods\n should attempt to do the operation in-place (modifying *self*) and\n return the result (which could be, but does not have to be,\n *self*). If a specific method is not defined, the augmented\n assignment falls back to the normal methods. For instance, to\n execute the statement ``x += y``, where *x* is an instance of a\n class that has an ``__iadd__()`` method, ``x.__iadd__(y)`` is\n called. If *x* is an instance of a class that does not define a\n ``__iadd__()`` method, ``x.__add__(y)`` and ``y.__radd__(x)`` are\n considered, as with the evaluation of ``x + y``.\n\nobject.__neg__(self)\nobject.__pos__(self)\nobject.__abs__(self)\nobject.__invert__(self)\n\n Called to implement the unary arithmetic operations (``-``, ``+``,\n ``abs()`` and ``~``).\n\nobject.__complex__(self)\nobject.__int__(self)\nobject.__float__(self)\nobject.__round__(self[, n])\n\n Called to implement the built-in functions ``complex()``,\n ``int()``, ``float()`` and ``round()``. Should return a value of\n the appropriate type.\n\nobject.__index__(self)\n\n Called to implement ``operator.index()``. Also called whenever\n Python needs an integer object (such as in slicing, or in the\n built-in ``bin()``, ``hex()`` and ``oct()`` functions). Must return\n an integer.\n", + 'objects': '\nObjects, values and types\n*************************\n\n*Objects* are Python\'s abstraction for data. All data in a Python\nprogram is represented by objects or by relations between objects. (In\na sense, and in conformance to Von Neumann\'s model of a "stored\nprogram computer," code is also represented by objects.)\n\nEvery object has an identity, a type and a value. An object\'s\n*identity* never changes once it has been created; you may think of it\nas the object\'s address in memory. The \'``is``\' operator compares the\nidentity of two objects; the ``id()`` function returns an integer\nrepresenting its identity (currently implemented as its address). An\nobject\'s *type* is also unchangeable. [1] An object\'s type determines\nthe operations that the object supports (e.g., "does it have a\nlength?") and also defines the possible values for objects of that\ntype. The ``type()`` function returns an object\'s type (which is an\nobject itself). The *value* of some objects can change. Objects\nwhose value can change are said to be *mutable*; objects whose value\nis unchangeable once they are created are called *immutable*. (The\nvalue of an immutable container object that contains a reference to a\nmutable object can change when the latter\'s value is changed; however\nthe container is still considered immutable, because the collection of\nobjects it contains cannot be changed. So, immutability is not\nstrictly the same as having an unchangeable value, it is more subtle.)\nAn object\'s mutability is determined by its type; for instance,\nnumbers, strings and tuples are immutable, while dictionaries and\nlists are mutable.\n\nObjects are never explicitly destroyed; however, when they become\nunreachable they may be garbage-collected. An implementation is\nallowed to postpone garbage collection or omit it altogether --- it is\na matter of implementation quality how garbage collection is\nimplemented, as long as no objects are collected that are still\nreachable.\n\n**CPython implementation detail:** CPython currently uses a reference-\ncounting scheme with (optional) delayed detection of cyclically linked\ngarbage, which collects most objects as soon as they become\nunreachable, but is not guaranteed to collect garbage containing\ncircular references. See the documentation of the ``gc`` module for\ninformation on controlling the collection of cyclic garbage. Other\nimplementations act differently and CPython may change. Do not depend\non immediate finalization of objects when they become unreachable (ex:\nalways close files).\n\nNote that the use of the implementation\'s tracing or debugging\nfacilities may keep objects alive that would normally be collectable.\nAlso note that catching an exception with a \'``try``...``except``\'\nstatement may keep objects alive.\n\nSome objects contain references to "external" resources such as open\nfiles or windows. It is understood that these resources are freed\nwhen the object is garbage-collected, but since garbage collection is\nnot guaranteed to happen, such objects also provide an explicit way to\nrelease the external resource, usually a ``close()`` method. Programs\nare strongly recommended to explicitly close such objects. The\n\'``try``...``finally``\' statement and the \'``with``\' statement provide\nconvenient ways to do this.\n\nSome objects contain references to other objects; these are called\n*containers*. Examples of containers are tuples, lists and\ndictionaries. The references are part of a container\'s value. In\nmost cases, when we talk about the value of a container, we imply the\nvalues, not the identities of the contained objects; however, when we\ntalk about the mutability of a container, only the identities of the\nimmediately contained objects are implied. So, if an immutable\ncontainer (like a tuple) contains a reference to a mutable object, its\nvalue changes if that mutable object is changed.\n\nTypes affect almost all aspects of object behavior. Even the\nimportance of object identity is affected in some sense: for immutable\ntypes, operations that compute new values may actually return a\nreference to any existing object with the same type and value, while\nfor mutable objects this is not allowed. E.g., after ``a = 1; b =\n1``, ``a`` and ``b`` may or may not refer to the same object with the\nvalue one, depending on the implementation, but after ``c = []; d =\n[]``, ``c`` and ``d`` are guaranteed to refer to two different,\nunique, newly created empty lists. (Note that ``c = d = []`` assigns\nthe same object to both ``c`` and ``d``.)\n', + 'operator-summary': '\nSummary\n*******\n\nThe following table summarizes the operator precedences in Python,\nfrom lowest precedence (least binding) to highest precedence (most\nbinding). Operators in the same box have the same precedence. Unless\nthe syntax is explicitly given, operators are binary. Operators in\nthe same box group left to right (except for comparisons, including\ntests, which all have the same precedence and chain from left to right\n--- see section *Comparisons* --- and exponentiation, which groups\nfrom right to left).\n\n+-------------------------------------------------+---------------------------------------+\n| Operator | Description |\n+=================================================+=======================================+\n| ``lambda`` | Lambda expression |\n+-------------------------------------------------+---------------------------------------+\n| ``if`` -- ``else`` | Conditional expression |\n+-------------------------------------------------+---------------------------------------+\n| ``or`` | Boolean OR |\n+-------------------------------------------------+---------------------------------------+\n| ``and`` | Boolean AND |\n+-------------------------------------------------+---------------------------------------+\n| ``not`` *x* | Boolean NOT |\n+-------------------------------------------------+---------------------------------------+\n| ``in``, ``not`` ``in``, ``is``, ``is not``, | Comparisons, including membership |\n| ``<``, ``<=``, ``>``, ``>=``, ``!=``, ``==`` | tests and identity tests, |\n+-------------------------------------------------+---------------------------------------+\n| ``|`` | Bitwise OR |\n+-------------------------------------------------+---------------------------------------+\n| ``^`` | Bitwise XOR |\n+-------------------------------------------------+---------------------------------------+\n| ``&`` | Bitwise AND |\n+-------------------------------------------------+---------------------------------------+\n| ``<<``, ``>>`` | Shifts |\n+-------------------------------------------------+---------------------------------------+\n| ``+``, ``-`` | Addition and subtraction |\n+-------------------------------------------------+---------------------------------------+\n| ``*``, ``/``, ``//``, ``%`` | Multiplication, division, remainder |\n| | [5] |\n+-------------------------------------------------+---------------------------------------+\n| ``+x``, ``-x``, ``~x`` | Positive, negative, bitwise NOT |\n+-------------------------------------------------+---------------------------------------+\n| ``**`` | Exponentiation [6] |\n+-------------------------------------------------+---------------------------------------+\n| ``x[index]``, ``x[index:index]``, | Subscription, slicing, call, |\n| ``x(arguments...)``, ``x.attribute`` | attribute reference |\n+-------------------------------------------------+---------------------------------------+\n| ``(expressions...)``, ``[expressions...]``, | Binding or tuple display, list |\n| ``{key:datum...}``, | display, dictionary display, |\n+-------------------------------------------------+---------------------------------------+\n\n-[ Footnotes ]-\n\n[1] While ``abs(x%y) < abs(y)`` is true mathematically, for floats it\n may not be true numerically due to roundoff. For example, and\n assuming a platform on which a Python float is an IEEE 754 double-\n precision number, in order that ``-1e-100 % 1e100`` have the same\n sign as ``1e100``, the computed result is ``-1e-100 + 1e100``,\n which is numerically exactly equal to ``1e100``. The function\n ``math.fmod()`` returns a result whose sign matches the sign of\n the first argument instead, and so returns ``-1e-100`` in this\n case. Which approach is more appropriate depends on the\n application.\n\n[2] If x is very close to an exact integer multiple of y, it\'s\n possible for ``x//y`` to be one larger than ``(x-x%y)//y`` due to\n rounding. In such cases, Python returns the latter result, in\n order to preserve that ``divmod(x,y)[0] * y + x % y`` be very\n close to ``x``.\n\n[3] While comparisons between strings make sense at the byte level,\n they may be counter-intuitive to users. For example, the strings\n ``"\\u00C7"`` and ``"\\u0327\\u0043"`` compare differently, even\n though they both represent the same unicode character (LATIN\n CAPITAL LETTER C WITH CEDILLA). To compare strings in a human\n recognizable way, compare using ``unicodedata.normalize()``.\n\n[4] Due to automatic garbage-collection, free lists, and the dynamic\n nature of descriptors, you may notice seemingly unusual behaviour\n in certain uses of the ``is`` operator, like those involving\n comparisons between instance methods, or constants. Check their\n documentation for more info.\n\n[5] The ``%`` operator is also used for string formatting; the same\n precedence applies.\n\n[6] The power operator ``**`` binds less tightly than an arithmetic or\n bitwise unary operator on its right, that is, ``2**-1`` is\n ``0.5``.\n', 'pass': '\nThe ``pass`` statement\n**********************\n\n pass_stmt ::= "pass"\n\n``pass`` is a null operation --- when it is executed, nothing happens.\nIt is useful as a placeholder when a statement is required\nsyntactically, but no code needs to be executed, for example:\n\n def f(arg): pass # a function that does nothing (yet)\n\n class C: pass # a class with no methods (yet)\n', 'power': '\nThe power operator\n******************\n\nThe power operator binds more tightly than unary operators on its\nleft; it binds less tightly than unary operators on its right. The\nsyntax is:\n\n power ::= primary ["**" u_expr]\n\nThus, in an unparenthesized sequence of power and unary operators, the\noperators are evaluated from right to left (this does not constrain\nthe evaluation order for the operands): ``-1**2`` results in ``-1``.\n\nThe power operator has the same semantics as the built-in ``pow()``\nfunction, when called with two arguments: it yields its left argument\nraised to the power of its right argument. The numeric arguments are\nfirst converted to a common type, and the result is of that type.\n\nFor int operands, the result has the same type as the operands unless\nthe second argument is negative; in that case, all arguments are\nconverted to float and a float result is delivered. For example,\n``10**2`` returns ``100``, but ``10**-2`` returns ``0.01``.\n\nRaising ``0.0`` to a negative power results in a\n``ZeroDivisionError``. Raising a negative number to a fractional power\nresults in a ``complex`` number. (In earlier versions it raised a\n``ValueError``.)\n', 'raise': '\nThe ``raise`` statement\n***********************\n\n raise_stmt ::= "raise" [expression ["from" expression]]\n\nIf no expressions are present, ``raise`` re-raises the last exception\nthat was active in the current scope. If no exception is active in\nthe current scope, a ``TypeError`` exception is raised indicating that\nthis is an error (if running under IDLE, a ``queue.Empty`` exception\nis raised instead).\n\nOtherwise, ``raise`` evaluates the first expression as the exception\nobject. It must be either a subclass or an instance of\n``BaseException``. If it is a class, the exception instance will be\nobtained when needed by instantiating the class with no arguments.\n\nThe *type* of the exception is the exception instance\'s class, the\n*value* is the instance itself.\n\nA traceback object is normally created automatically when an exception\nis raised and attached to it as the ``__traceback__`` attribute, which\nis writable. You can create an exception and set your own traceback in\none step using the ``with_traceback()`` exception method (which\nreturns the same exception instance, with its traceback set to its\nargument), like so:\n\n raise Exception("foo occurred").with_traceback(tracebackobj)\n\nThe ``from`` clause is used for exception chaining: if given, the\nsecond *expression* must be another exception class or instance, which\nwill then be attached to the raised exception as the ``__cause__``\nattribute (which is writable). If the raised exception is not\nhandled, both exceptions will be printed:\n\n >>> try:\n ... print(1 / 0)\n ... except Exception as exc:\n ... raise RuntimeError("Something bad happened") from exc\n ...\n Traceback (most recent call last):\n File "", line 2, in \n ZeroDivisionError: int division or modulo by zero\n\n The above exception was the direct cause of the following exception:\n\n Traceback (most recent call last):\n File "", line 4, in \n RuntimeError: Something bad happened\n\nA similar mechanism works implicitly if an exception is raised inside\nan exception handler: the previous exception is then attached as the\nnew exception\'s ``__context__`` attribute:\n\n >>> try:\n ... print(1 / 0)\n ... except:\n ... raise RuntimeError("Something bad happened")\n ...\n Traceback (most recent call last):\n File "", line 2, in \n ZeroDivisionError: int division or modulo by zero\n\n During handling of the above exception, another exception occurred:\n\n Traceback (most recent call last):\n File "", line 4, in \n RuntimeError: Something bad happened\n\nAdditional information on exceptions can be found in section\n*Exceptions*, and information about handling exceptions is in section\n*The try statement*.\n', 'return': '\nThe ``return`` statement\n************************\n\n return_stmt ::= "return" [expression_list]\n\n``return`` may only occur syntactically nested in a function\ndefinition, not within a nested class definition.\n\nIf an expression list is present, it is evaluated, else ``None`` is\nsubstituted.\n\n``return`` leaves the current function call with the expression list\n(or ``None``) as return value.\n\nWhen ``return`` passes control out of a ``try`` statement with a\n``finally`` clause, that ``finally`` clause is executed before really\nleaving the function.\n\nIn a generator function, the ``return`` statement is not allowed to\ninclude an **expression_list**. In that context, a bare ``return``\nindicates that the generator is done and will cause ``StopIteration``\nto be raised.\n', - 'sequence-types': "\nEmulating container types\n*************************\n\nThe following methods can be defined to implement container objects.\nContainers usually are sequences (such as lists or tuples) or mappings\n(like dictionaries), but can represent other containers as well. The\nfirst set of methods is used either to emulate a sequence or to\nemulate a mapping; the difference is that for a sequence, the\nallowable keys should be the integers *k* for which ``0 <= k < N``\nwhere *N* is the length of the sequence, or slice objects, which\ndefine a range of items. It is also recommended that mappings provide\nthe methods ``keys()``, ``values()``, ``items()``, ``get()``,\n``clear()``, ``setdefault()``, ``pop()``, ``popitem()``, ``copy()``,\nand ``update()`` behaving similar to those for Python's standard\ndictionary objects. The ``collections`` module provides a\n``MutableMapping`` abstract base class to help create those methods\nfrom a base set of ``__getitem__()``, ``__setitem__()``,\n``__delitem__()``, and ``keys()``. Mutable sequences should provide\nmethods ``append()``, ``count()``, ``index()``, ``extend()``,\n``insert()``, ``pop()``, ``remove()``, ``reverse()`` and ``sort()``,\nlike Python standard list objects. Finally, sequence types should\nimplement addition (meaning concatenation) and multiplication (meaning\nrepetition) by defining the methods ``__add__()``, ``__radd__()``,\n``__iadd__()``, ``__mul__()``, ``__rmul__()`` and ``__imul__()``\ndescribed below; they should not define other numerical operators. It\nis recommended that both mappings and sequences implement the\n``__contains__()`` method to allow efficient use of the ``in``\noperator; for mappings, ``in`` should search the mapping's keys; for\nsequences, it should search through the values. It is further\nrecommended that both mappings and sequences implement the\n``__iter__()`` method to allow efficient iteration through the\ncontainer; for mappings, ``__iter__()`` should be the same as\n``keys()``; for sequences, it should iterate through the values.\n\nobject.__len__(self)\n\n Called to implement the built-in function ``len()``. Should return\n the length of the object, an integer ``>=`` 0. Also, an object\n that doesn't define a ``__bool__()`` method and whose ``__len__()``\n method returns zero is considered to be false in a Boolean context.\n\nNote: Slicing is done exclusively with the following three methods. A\n call like\n\n a[1:2] = b\n\n is translated to\n\n a[slice(1, 2, None)] = b\n\n and so forth. Missing slice items are always filled in with\n ``None``.\n\nobject.__getitem__(self, key)\n\n Called to implement evaluation of ``self[key]``. For sequence\n types, the accepted keys should be integers and slice objects.\n Note that the special interpretation of negative indexes (if the\n class wishes to emulate a sequence type) is up to the\n ``__getitem__()`` method. If *key* is of an inappropriate type,\n ``TypeError`` may be raised; if of a value outside the set of\n indexes for the sequence (after any special interpretation of\n negative values), ``IndexError`` should be raised. For mapping\n types, if *key* is missing (not in the container), ``KeyError``\n should be raised.\n\n Note: ``for`` loops expect that an ``IndexError`` will be raised for\n illegal indexes to allow proper detection of the end of the\n sequence.\n\nobject.__setitem__(self, key, value)\n\n Called to implement assignment to ``self[key]``. Same note as for\n ``__getitem__()``. This should only be implemented for mappings if\n the objects support changes to the values for keys, or if new keys\n can be added, or for sequences if elements can be replaced. The\n same exceptions should be raised for improper *key* values as for\n the ``__getitem__()`` method.\n\nobject.__delitem__(self, key)\n\n Called to implement deletion of ``self[key]``. Same note as for\n ``__getitem__()``. This should only be implemented for mappings if\n the objects support removal of keys, or for sequences if elements\n can be removed from the sequence. The same exceptions should be\n raised for improper *key* values as for the ``__getitem__()``\n method.\n\nobject.__iter__(self)\n\n This method is called when an iterator is required for a container.\n This method should return a new iterator object that can iterate\n over all the objects in the container. For mappings, it should\n iterate over the keys of the container, and should also be made\n available as the method ``keys()``.\n\n Iterator objects also need to implement this method; they are\n required to return themselves. For more information on iterator\n objects, see *Iterator Types*.\n\nobject.__reversed__(self)\n\n Called (if present) by the ``reversed()`` builtin to implement\n reverse iteration. It should return a new iterator object that\n iterates over all the objects in the container in reverse order.\n\n If the ``__reversed__()`` method is not provided, the\n ``reversed()`` builtin will fall back to using the sequence\n protocol (``__len__()`` and ``__getitem__()``). Objects that\n support the sequence protocol should only provide\n ``__reversed__()`` if they can provide an implementation that is\n more efficient than the one provided by ``reversed()``.\n\nThe membership test operators (``in`` and ``not in``) are normally\nimplemented as an iteration through a sequence. However, container\nobjects can supply the following special method with a more efficient\nimplementation, which also does not require the object be a sequence.\n\nobject.__contains__(self, item)\n\n Called to implement membership test operators. Should return true\n if *item* is in *self*, false otherwise. For mapping objects, this\n should consider the keys of the mapping rather than the values or\n the key-item pairs.\n", + 'sequence-types': "\nEmulating container types\n*************************\n\nThe following methods can be defined to implement container objects.\nContainers usually are sequences (such as lists or tuples) or mappings\n(like dictionaries), but can represent other containers as well. The\nfirst set of methods is used either to emulate a sequence or to\nemulate a mapping; the difference is that for a sequence, the\nallowable keys should be the integers *k* for which ``0 <= k < N``\nwhere *N* is the length of the sequence, or slice objects, which\ndefine a range of items. It is also recommended that mappings provide\nthe methods ``keys()``, ``values()``, ``items()``, ``get()``,\n``clear()``, ``setdefault()``, ``pop()``, ``popitem()``, ``copy()``,\nand ``update()`` behaving similar to those for Python's standard\ndictionary objects. The ``collections`` module provides a\n``MutableMapping`` abstract base class to help create those methods\nfrom a base set of ``__getitem__()``, ``__setitem__()``,\n``__delitem__()``, and ``keys()``. Mutable sequences should provide\nmethods ``append()``, ``count()``, ``index()``, ``extend()``,\n``insert()``, ``pop()``, ``remove()``, ``reverse()`` and ``sort()``,\nlike Python standard list objects. Finally, sequence types should\nimplement addition (meaning concatenation) and multiplication (meaning\nrepetition) by defining the methods ``__add__()``, ``__radd__()``,\n``__iadd__()``, ``__mul__()``, ``__rmul__()`` and ``__imul__()``\ndescribed below; they should not define other numerical operators. It\nis recommended that both mappings and sequences implement the\n``__contains__()`` method to allow efficient use of the ``in``\noperator; for mappings, ``in`` should search the mapping's keys; for\nsequences, it should search through the values. It is further\nrecommended that both mappings and sequences implement the\n``__iter__()`` method to allow efficient iteration through the\ncontainer; for mappings, ``__iter__()`` should be the same as\n``keys()``; for sequences, it should iterate through the values.\n\nobject.__len__(self)\n\n Called to implement the built-in function ``len()``. Should return\n the length of the object, an integer ``>=`` 0. Also, an object\n that doesn't define a ``__bool__()`` method and whose ``__len__()``\n method returns zero is considered to be false in a Boolean context.\n\nNote: Slicing is done exclusively with the following three methods. A\n call like\n\n a[1:2] = b\n\n is translated to\n\n a[slice(1, 2, None)] = b\n\n and so forth. Missing slice items are always filled in with\n ``None``.\n\nobject.__getitem__(self, key)\n\n Called to implement evaluation of ``self[key]``. For sequence\n types, the accepted keys should be integers and slice objects.\n Note that the special interpretation of negative indexes (if the\n class wishes to emulate a sequence type) is up to the\n ``__getitem__()`` method. If *key* is of an inappropriate type,\n ``TypeError`` may be raised; if of a value outside the set of\n indexes for the sequence (after any special interpretation of\n negative values), ``IndexError`` should be raised. For mapping\n types, if *key* is missing (not in the container), ``KeyError``\n should be raised.\n\n Note: ``for`` loops expect that an ``IndexError`` will be raised for\n illegal indexes to allow proper detection of the end of the\n sequence.\n\nobject.__setitem__(self, key, value)\n\n Called to implement assignment to ``self[key]``. Same note as for\n ``__getitem__()``. This should only be implemented for mappings if\n the objects support changes to the values for keys, or if new keys\n can be added, or for sequences if elements can be replaced. The\n same exceptions should be raised for improper *key* values as for\n the ``__getitem__()`` method.\n\nobject.__delitem__(self, key)\n\n Called to implement deletion of ``self[key]``. Same note as for\n ``__getitem__()``. This should only be implemented for mappings if\n the objects support removal of keys, or for sequences if elements\n can be removed from the sequence. The same exceptions should be\n raised for improper *key* values as for the ``__getitem__()``\n method.\n\nobject.__iter__(self)\n\n This method is called when an iterator is required for a container.\n This method should return a new iterator object that can iterate\n over all the objects in the container. For mappings, it should\n iterate over the keys of the container, and should also be made\n available as the method ``keys()``.\n\n Iterator objects also need to implement this method; they are\n required to return themselves. For more information on iterator\n objects, see *Iterator Types*.\n\nobject.__reversed__(self)\n\n Called (if present) by the ``reversed()`` built-in to implement\n reverse iteration. It should return a new iterator object that\n iterates over all the objects in the container in reverse order.\n\n If the ``__reversed__()`` method is not provided, the\n ``reversed()`` built-in will fall back to using the sequence\n protocol (``__len__()`` and ``__getitem__()``). Objects that\n support the sequence protocol should only provide\n ``__reversed__()`` if they can provide an implementation that is\n more efficient than the one provided by ``reversed()``.\n\nThe membership test operators (``in`` and ``not in``) are normally\nimplemented as an iteration through a sequence. However, container\nobjects can supply the following special method with a more efficient\nimplementation, which also does not require the object be a sequence.\n\nobject.__contains__(self, item)\n\n Called to implement membership test operators. Should return true\n if *item* is in *self*, false otherwise. For mapping objects, this\n should consider the keys of the mapping rather than the values or\n the key-item pairs.\n\n For objects that don't define ``__contains__()``, the membership\n test first tries iteration via ``__iter__()``, then the old\n sequence iteration protocol via ``__getitem__()``, see *this\n section in the language reference*.\n", 'shifting': '\nShifting operations\n*******************\n\nThe shifting operations have lower priority than the arithmetic\noperations:\n\n shift_expr ::= a_expr | shift_expr ( "<<" | ">>" ) a_expr\n\nThese operators accept integers as arguments. They shift the first\nargument to the left or right by the number of bits given by the\nsecond argument.\n\nA right shift by *n* bits is defined as division by ``pow(2,n)``. A\nleft shift by *n* bits is defined as multiplication with ``pow(2,n)``.\n', 'slicings': '\nSlicings\n********\n\nA slicing selects a range of items in a sequence object (e.g., a\nstring, tuple or list). Slicings may be used as expressions or as\ntargets in assignment or ``del`` statements. The syntax for a\nslicing:\n\n slicing ::= primary "[" slice_list "]"\n slice_list ::= slice_item ("," slice_item)* [","]\n slice_item ::= expression | proper_slice\n proper_slice ::= [lower_bound] ":" [upper_bound] [ ":" [stride] ]\n lower_bound ::= expression\n upper_bound ::= expression\n stride ::= expression\n\nThere is ambiguity in the formal syntax here: anything that looks like\nan expression list also looks like a slice list, so any subscription\ncan be interpreted as a slicing. Rather than further complicating the\nsyntax, this is disambiguated by defining that in this case the\ninterpretation as a subscription takes priority over the\ninterpretation as a slicing (this is the case if the slice list\ncontains no proper slice).\n\nThe semantics for a slicing are as follows. The primary must evaluate\nto a mapping object, and it is indexed (using the same\n``__getitem__()`` method as normal subscription) with a key that is\nconstructed from the slice list, as follows. If the slice list\ncontains at least one comma, the key is a tuple containing the\nconversion of the slice items; otherwise, the conversion of the lone\nslice item is the key. The conversion of a slice item that is an\nexpression is that expression. The conversion of a proper slice is a\nslice object (see section *The standard type hierarchy*) whose\n``start``, ``stop`` and ``step`` attributes are the values of the\nexpressions given as lower bound, upper bound and stride,\nrespectively, substituting ``None`` for missing expressions.\n', - 'specialattrs': "\nSpecial Attributes\n******************\n\nThe implementation adds a few special read-only attributes to several\nobject types, where they are relevant. Some of these are not reported\nby the ``dir()`` built-in function.\n\nobject.__dict__\n\n A dictionary or other mapping object used to store an object's\n (writable) attributes.\n\ninstance.__class__\n\n The class to which a class instance belongs.\n\nclass.__bases__\n\n The tuple of base classes of a class object. If there are no base\n classes, this will be an empty tuple.\n\nclass.__name__\n\n The name of the class or type.\n\nThe following attributes are only supported by *new-style class*es.\n\nclass.__mro__\n\n This attribute is a tuple of classes that are considered when\n looking for base classes during method resolution.\n\nclass.mro()\n\n This method can be overridden by a metaclass to customize the\n method resolution order for its instances. It is called at class\n instantiation, and its result is stored in ``__mro__``.\n\nclass.__subclasses__()\n\n Each new-style class keeps a list of weak references to its\n immediate subclasses. This method returns a list of all those\n references still alive. Example:\n\n >>> int.__subclasses__()\n []\n\n-[ Footnotes ]-\n\n[1] Additional information on these special methods may be found in\n the Python Reference Manual (*Basic customization*).\n\n[2] As a consequence, the list ``[1, 2]`` is considered equal to\n ``[1.0, 2.0]``, and similarly for tuples.\n\n[3] They must have since the parser can't tell the type of the\n operands.\n\n[4] To format only a tuple you should therefore provide a singleton\n tuple whose only element is the tuple to be formatted.\n\n[5] The advantage of leaving the newline on is that returning an empty\n string is then an unambiguous EOF indication. It is also possible\n (in cases where it might matter, for example, if you want to make\n an exact copy of a file while scanning its lines) to tell whether\n the last line of a file ended in a newline or not (yes this\n happens!).\n", - 'specialnames': '\nSpecial method names\n********************\n\nA class can implement certain operations that are invoked by special\nsyntax (such as arithmetic operations or subscripting and slicing) by\ndefining methods with special names. This is Python\'s approach to\n*operator overloading*, allowing classes to define their own behavior\nwith respect to language operators. For instance, if a class defines\na method named ``__getitem__()``, and ``x`` is an instance of this\nclass, then ``x[i]`` is roughly equivalent to ``type(x).__getitem__(x,\ni)``. Except where mentioned, attempts to execute an operation raise\nan exception when no appropriate method is defined (typically\n``AttributeError`` or ``TypeError``).\n\nWhen implementing a class that emulates any built-in type, it is\nimportant that the emulation only be implemented to the degree that it\nmakes sense for the object being modelled. For example, some\nsequences may work well with retrieval of individual elements, but\nextracting a slice may not make sense. (One example of this is the\n``NodeList`` interface in the W3C\'s Document Object Model.)\n\n\nBasic customization\n===================\n\nobject.__new__(cls[, ...])\n\n Called to create a new instance of class *cls*. ``__new__()`` is a\n static method (special-cased so you need not declare it as such)\n that takes the class of which an instance was requested as its\n first argument. The remaining arguments are those passed to the\n object constructor expression (the call to the class). The return\n value of ``__new__()`` should be the new object instance (usually\n an instance of *cls*).\n\n Typical implementations create a new instance of the class by\n invoking the superclass\'s ``__new__()`` method using\n ``super(currentclass, cls).__new__(cls[, ...])`` with appropriate\n arguments and then modifying the newly-created instance as\n necessary before returning it.\n\n If ``__new__()`` returns an instance of *cls*, then the new\n instance\'s ``__init__()`` method will be invoked like\n ``__init__(self[, ...])``, where *self* is the new instance and the\n remaining arguments are the same as were passed to ``__new__()``.\n\n If ``__new__()`` does not return an instance of *cls*, then the new\n instance\'s ``__init__()`` method will not be invoked.\n\n ``__new__()`` is intended mainly to allow subclasses of immutable\n types (like int, str, or tuple) to customize instance creation. It\n is also commonly overridden in custom metaclasses in order to\n customize class creation.\n\nobject.__init__(self[, ...])\n\n Called when the instance is created. The arguments are those\n passed to the class constructor expression. If a base class has an\n ``__init__()`` method, the derived class\'s ``__init__()`` method,\n if any, must explicitly call it to ensure proper initialization of\n the base class part of the instance; for example:\n ``BaseClass.__init__(self, [args...])``. As a special constraint\n on constructors, no value may be returned; doing so will cause a\n ``TypeError`` to be raised at runtime.\n\nobject.__del__(self)\n\n Called when the instance is about to be destroyed. This is also\n called a destructor. If a base class has a ``__del__()`` method,\n the derived class\'s ``__del__()`` method, if any, must explicitly\n call it to ensure proper deletion of the base class part of the\n instance. Note that it is possible (though not recommended!) for\n the ``__del__()`` method to postpone destruction of the instance by\n creating a new reference to it. It may then be called at a later\n time when this new reference is deleted. It is not guaranteed that\n ``__del__()`` methods are called for objects that still exist when\n the interpreter exits.\n\n Note: ``del x`` doesn\'t directly call ``x.__del__()`` --- the former\n decrements the reference count for ``x`` by one, and the latter\n is only called when ``x``\'s reference count reaches zero. Some\n common situations that may prevent the reference count of an\n object from going to zero include: circular references between\n objects (e.g., a doubly-linked list or a tree data structure with\n parent and child pointers); a reference to the object on the\n stack frame of a function that caught an exception (the traceback\n stored in ``sys.exc_info()[2]`` keeps the stack frame alive); or\n a reference to the object on the stack frame that raised an\n unhandled exception in interactive mode (the traceback stored in\n ``sys.last_traceback`` keeps the stack frame alive). The first\n situation can only be remedied by explicitly breaking the cycles;\n the latter two situations can be resolved by storing ``None`` in\n ``sys.last_traceback``. Circular references which are garbage are\n detected when the option cycle detector is enabled (it\'s on by\n default), but can only be cleaned up if there are no Python-\n level ``__del__()`` methods involved. Refer to the documentation\n for the ``gc`` module for more information about how\n ``__del__()`` methods are handled by the cycle detector,\n particularly the description of the ``garbage`` value.\n\n Warning: Due to the precarious circumstances under which ``__del__()``\n methods are invoked, exceptions that occur during their execution\n are ignored, and a warning is printed to ``sys.stderr`` instead.\n Also, when ``__del__()`` is invoked in response to a module being\n deleted (e.g., when execution of the program is done), other\n globals referenced by the ``__del__()`` method may already have\n been deleted or in the process of being torn down (e.g. the\n import machinery shutting down). For this reason, ``__del__()``\n methods should do the absolute minimum needed to maintain\n external invariants. Starting with version 1.5, Python\n guarantees that globals whose name begins with a single\n underscore are deleted from their module before other globals are\n deleted; if no other references to such globals exist, this may\n help in assuring that imported modules are still available at the\n time when the ``__del__()`` method is called.\n\nobject.__repr__(self)\n\n Called by the ``repr()`` built-in function to compute the\n "official" string representation of an object. If at all possible,\n this should look like a valid Python expression that could be used\n to recreate an object with the same value (given an appropriate\n environment). If this is not possible, a string of the form\n ``<...some useful description...>`` should be returned. The return\n value must be a string object. If a class defines ``__repr__()``\n but not ``__str__()``, then ``__repr__()`` is also used when an\n "informal" string representation of instances of that class is\n required.\n\n This is typically used for debugging, so it is important that the\n representation is information-rich and unambiguous.\n\nobject.__str__(self)\n\n Called by the ``str()`` built-in function and by the ``print()``\n function to compute the "informal" string representation of an\n object. This differs from ``__repr__()`` in that it does not have\n to be a valid Python expression: a more convenient or concise\n representation may be used instead. The return value must be a\n string object.\n\nobject.__format__(self, format_spec)\n\n Called by the ``format()`` built-in function (and by extension, the\n ``format()`` method of class ``str``) to produce a "formatted"\n string representation of an object. The ``format_spec`` argument is\n a string that contains a description of the formatting options\n desired. The interpretation of the ``format_spec`` argument is up\n to the type implementing ``__format__()``, however most classes\n will either delegate formatting to one of the built-in types, or\n use a similar formatting option syntax.\n\n See *Format Specification Mini-Language* for a description of the\n standard formatting syntax.\n\n The return value must be a string object.\n\nobject.__lt__(self, other)\nobject.__le__(self, other)\nobject.__eq__(self, other)\nobject.__ne__(self, other)\nobject.__gt__(self, other)\nobject.__ge__(self, other)\n\n These are the so-called "rich comparison" methods. The\n correspondence between operator symbols and method names is as\n follows: ``xy`` calls ``x.__gt__(y)``, and ``x>=y`` calls\n ``x.__ge__(y)``.\n\n A rich comparison method may return the singleton\n ``NotImplemented`` if it does not implement the operation for a\n given pair of arguments. By convention, ``False`` and ``True`` are\n returned for a successful comparison. However, these methods can\n return any value, so if the comparison operator is used in a\n Boolean context (e.g., in the condition of an ``if`` statement),\n Python will call ``bool()`` on the value to determine if the result\n is true or false.\n\n There are no implied relationships among the comparison operators.\n The truth of ``x==y`` does not imply that ``x!=y`` is false.\n Accordingly, when defining ``__eq__()``, one should also define\n ``__ne__()`` so that the operators will behave as expected. See\n the paragraph on ``__hash__()`` for some important notes on\n creating *hashable* objects which support custom comparison\n operations and are usable as dictionary keys.\n\n There are no swapped-argument versions of these methods (to be used\n when the left argument does not support the operation but the right\n argument does); rather, ``__lt__()`` and ``__gt__()`` are each\n other\'s reflection, ``__le__()`` and ``__ge__()`` are each other\'s\n reflection, and ``__eq__()`` and ``__ne__()`` are their own\n reflection.\n\n Arguments to rich comparison methods are never coerced.\n\n To automatically generate ordering operations from a single root\n operation, see the Total Ordering recipe in the ASPN cookbook.\n\nobject.__hash__(self)\n\n Called by built-in function ``hash()`` and for operations on\n members of hashed collections including ``set``, ``frozenset``, and\n ``dict``. ``__hash__()`` should return an integer. The only\n required property is that objects which compare equal have the same\n hash value; it is advised to somehow mix together (e.g. using\n exclusive or) the hash values for the components of the object that\n also play a part in comparison of objects.\n\n If a class does not define an ``__eq__()`` method it should not\n define a ``__hash__()`` operation either; if it defines\n ``__eq__()`` but not ``__hash__()``, its instances will not be\n usable as items in hashable collections. If a class defines\n mutable objects and implements an ``__eq__()`` method, it should\n not implement ``__hash__()``, since the implementation of hashable\n collections requires that a key\'s hash value is immutable (if the\n object\'s hash value changes, it will be in the wrong hash bucket).\n\n User-defined classes have ``__eq__()`` and ``__hash__()`` methods\n by default; with them, all objects compare unequal (except with\n themselves) and ``x.__hash__()`` returns ``id(x)``.\n\n Classes which inherit a ``__hash__()`` method from a parent class\n but change the meaning of ``__eq__()`` such that the hash value\n returned is no longer appropriate (e.g. by switching to a value-\n based concept of equality instead of the default identity based\n equality) can explicitly flag themselves as being unhashable by\n setting ``__hash__ = None`` in the class definition. Doing so means\n that not only will instances of the class raise an appropriate\n ``TypeError`` when a program attempts to retrieve their hash value,\n but they will also be correctly identified as unhashable when\n checking ``isinstance(obj, collections.Hashable)`` (unlike classes\n which define their own ``__hash__()`` to explicitly raise\n ``TypeError``).\n\n If a class that overrides ``__eq__()`` needs to retain the\n implementation of ``__hash__()`` from a parent class, the\n interpreter must be told this explicitly by setting ``__hash__ =\n .__hash__``. Otherwise the inheritance of\n ``__hash__()`` will be blocked, just as if ``__hash__`` had been\n explicitly set to ``None``.\n\nobject.__bool__(self)\n\n Called to implement truth value testing and the built-in operation\n ``bool()``; should return ``False`` or ``True``, or their integer\n equivalents ``0`` or ``1``. When this method is not defined,\n ``__len__()`` is called, if it is defined, and the object is\n considered true if its result is nonzero. If a class defines\n neither ``__len__()`` nor ``__bool__()``, all its instances are\n considered true.\n\n\nCustomizing attribute access\n============================\n\nThe following methods can be defined to customize the meaning of\nattribute access (use of, assignment to, or deletion of ``x.name``)\nfor class instances.\n\nobject.__getattr__(self, name)\n\n Called when an attribute lookup has not found the attribute in the\n usual places (i.e. it is not an instance attribute nor is it found\n in the class tree for ``self``). ``name`` is the attribute name.\n This method should return the (computed) attribute value or raise\n an ``AttributeError`` exception.\n\n Note that if the attribute is found through the normal mechanism,\n ``__getattr__()`` is not called. (This is an intentional asymmetry\n between ``__getattr__()`` and ``__setattr__()``.) This is done both\n for efficiency reasons and because otherwise ``__getattr__()``\n would have no way to access other attributes of the instance. Note\n that at least for instance variables, you can fake total control by\n not inserting any values in the instance attribute dictionary (but\n instead inserting them in another object). See the\n ``__getattribute__()`` method below for a way to actually get total\n control over attribute access.\n\nobject.__getattribute__(self, name)\n\n Called unconditionally to implement attribute accesses for\n instances of the class. If the class also defines\n ``__getattr__()``, the latter will not be called unless\n ``__getattribute__()`` either calls it explicitly or raises an\n ``AttributeError``. This method should return the (computed)\n attribute value or raise an ``AttributeError`` exception. In order\n to avoid infinite recursion in this method, its implementation\n should always call the base class method with the same name to\n access any attributes it needs, for example,\n ``object.__getattribute__(self, name)``.\n\n Note: This method may still be bypassed when looking up special methods\n as the result of implicit invocation via language syntax or\n builtin functions. See *Special method lookup*.\n\nobject.__setattr__(self, name, value)\n\n Called when an attribute assignment is attempted. This is called\n instead of the normal mechanism (i.e. store the value in the\n instance dictionary). *name* is the attribute name, *value* is the\n value to be assigned to it.\n\n If ``__setattr__()`` wants to assign to an instance attribute, it\n should call the base class method with the same name, for example,\n ``object.__setattr__(self, name, value)``.\n\nobject.__delattr__(self, name)\n\n Like ``__setattr__()`` but for attribute deletion instead of\n assignment. This should only be implemented if ``del obj.name`` is\n meaningful for the object.\n\nobject.__dir__(self)\n\n Called when ``dir()`` is called on the object. A list must be\n returned.\n\n\nImplementing Descriptors\n------------------------\n\nThe following methods only apply when an instance of the class\ncontaining the method (a so-called *descriptor* class) appears in the\nclass dictionary of another class, known as the *owner* class. In the\nexamples below, "the attribute" refers to the attribute whose name is\nthe key of the property in the owner class\' ``__dict__``.\n\nobject.__get__(self, instance, owner)\n\n Called to get the attribute of the owner class (class attribute\n access) or of an instance of that class (instance attribute\n access). *owner* is always the owner class, while *instance* is the\n instance that the attribute was accessed through, or ``None`` when\n the attribute is accessed through the *owner*. This method should\n return the (computed) attribute value or raise an\n ``AttributeError`` exception.\n\nobject.__set__(self, instance, value)\n\n Called to set the attribute on an instance *instance* of the owner\n class to a new value, *value*.\n\nobject.__delete__(self, instance)\n\n Called to delete the attribute on an instance *instance* of the\n owner class.\n\n\nInvoking Descriptors\n--------------------\n\nIn general, a descriptor is an object attribute with "binding\nbehavior", one whose attribute access has been overridden by methods\nin the descriptor protocol: ``__get__()``, ``__set__()``, and\n``__delete__()``. If any of those methods are defined for an object,\nit is said to be a descriptor.\n\nThe default behavior for attribute access is to get, set, or delete\nthe attribute from an object\'s dictionary. For instance, ``a.x`` has a\nlookup chain starting with ``a.__dict__[\'x\']``, then\n``type(a).__dict__[\'x\']``, and continuing through the base classes of\n``type(a)`` excluding metaclasses.\n\nHowever, if the looked-up value is an object defining one of the\ndescriptor methods, then Python may override the default behavior and\ninvoke the descriptor method instead. Where this occurs in the\nprecedence chain depends on which descriptor methods were defined and\nhow they were called.\n\nThe starting point for descriptor invocation is a binding, ``a.x``.\nHow the arguments are assembled depends on ``a``:\n\nDirect Call\n The simplest and least common call is when user code directly\n invokes a descriptor method: ``x.__get__(a)``.\n\nInstance Binding\n If binding to an object instance, ``a.x`` is transformed into the\n call: ``type(a).__dict__[\'x\'].__get__(a, type(a))``.\n\nClass Binding\n If binding to a class, ``A.x`` is transformed into the call:\n ``A.__dict__[\'x\'].__get__(None, A)``.\n\nSuper Binding\n If ``a`` is an instance of ``super``, then the binding ``super(B,\n obj).m()`` searches ``obj.__class__.__mro__`` for the base class\n ``A`` immediately preceding ``B`` and then invokes the descriptor\n with the call: ``A.__dict__[\'m\'].__get__(obj, A)``.\n\nFor instance bindings, the precedence of descriptor invocation depends\non the which descriptor methods are defined. Normally, data\ndescriptors define both ``__get__()`` and ``__set__()``, while non-\ndata descriptors have just the ``__get__()`` method. Data descriptors\nalways override a redefinition in an instance dictionary. In\ncontrast, non-data descriptors can be overridden by instances. [2]\n\nPython methods (including ``staticmethod()`` and ``classmethod()``)\nare implemented as non-data descriptors. Accordingly, instances can\nredefine and override methods. This allows individual instances to\nacquire behaviors that differ from other instances of the same class.\n\nThe ``property()`` function is implemented as a data descriptor.\nAccordingly, instances cannot override the behavior of a property.\n\n\n__slots__\n---------\n\nBy default, instances of classes have a dictionary for attribute\nstorage. This wastes space for objects having very few instance\nvariables. The space consumption can become acute when creating large\nnumbers of instances.\n\nThe default can be overridden by defining *__slots__* in a class\ndefinition. The *__slots__* declaration takes a sequence of instance\nvariables and reserves just enough space in each instance to hold a\nvalue for each variable. Space is saved because *__dict__* is not\ncreated for each instance.\n\nobject.__slots__\n\n This class variable can be assigned a string, iterable, or sequence\n of strings with variable names used by instances. If defined in a\n class, *__slots__* reserves space for the declared variables and\n prevents the automatic creation of *__dict__* and *__weakref__* for\n each instance.\n\n\nNotes on using *__slots__*\n~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n* When inheriting from a class without *__slots__*, the *__dict__*\n attribute of that class will always be accessible, so a *__slots__*\n definition in the subclass is meaningless.\n\n* Without a *__dict__* variable, instances cannot be assigned new\n variables not listed in the *__slots__* definition. Attempts to\n assign to an unlisted variable name raises ``AttributeError``. If\n dynamic assignment of new variables is desired, then add\n ``\'__dict__\'`` to the sequence of strings in the *__slots__*\n declaration.\n\n* Without a *__weakref__* variable for each instance, classes defining\n *__slots__* do not support weak references to its instances. If weak\n reference support is needed, then add ``\'__weakref__\'`` to the\n sequence of strings in the *__slots__* declaration.\n\n* *__slots__* are implemented at the class level by creating\n descriptors (*Implementing Descriptors*) for each variable name. As\n a result, class attributes cannot be used to set default values for\n instance variables defined by *__slots__*; otherwise, the class\n attribute would overwrite the descriptor assignment.\n\n* If a class defines a slot also defined in a base class, the instance\n variable defined by the base class slot is inaccessible (except by\n retrieving its descriptor directly from the base class). This\n renders the meaning of the program undefined. In the future, a\n check may be added to prevent this.\n\n* The action of a *__slots__* declaration is limited to the class\n where it is defined. As a result, subclasses will have a *__dict__*\n unless they also define *__slots__*.\n\n* Nonempty *__slots__* does not work for classes derived from\n "variable-length" built-in types such as ``int``, ``str`` and\n ``tuple``.\n\n* Any non-string iterable may be assigned to *__slots__*. Mappings may\n also be used; however, in the future, special meaning may be\n assigned to the values corresponding to each key.\n\n* *__class__* assignment works only if both classes have the same\n *__slots__*.\n\n\nCustomizing class creation\n==========================\n\nBy default, classes are constructed using ``type()``. A class\ndefinition is read into a separate namespace and the value of class\nname is bound to the result of ``type(name, bases, dict)``.\n\nWhen the class definition is read, if a callable ``metaclass`` keyword\nargument is passed after the bases in the class definition, the\ncallable given will be called instead of ``type()``. If other keyword\narguments are passed, they will also be passed to the metaclass. This\nallows classes or functions to be written which monitor or alter the\nclass creation process:\n\n* Modifying the class dictionary prior to the class being created.\n\n* Returning an instance of another class -- essentially performing the\n role of a factory function.\n\nThese steps will have to be performed in the metaclass\'s ``__new__()``\nmethod -- ``type.__new__()`` can then be called from this method to\ncreate a class with different properties. This example adds a new\nelement to the class dictionary before creating the class:\n\n class metacls(type):\n def __new__(mcs, name, bases, dict):\n dict[\'foo\'] = \'metacls was here\'\n return type.__new__(mcs, name, bases, dict)\n\nYou can of course also override other class methods (or add new\nmethods); for example defining a custom ``__call__()`` method in the\nmetaclass allows custom behavior when the class is called, e.g. not\nalways creating a new instance.\n\nIf the metaclass has a ``__prepare__()`` attribute (usually\nimplemented as a class or static method), it is called before the\nclass body is evaluated with the name of the class and a tuple of its\nbases for arguments. It should return an object that supports the\nmapping interface that will be used to store the namespace of the\nclass. The default is a plain dictionary. This could be used, for\nexample, to keep track of the order that class attributes are declared\nin by returning an ordered dictionary.\n\nThe appropriate metaclass is determined by the following precedence\nrules:\n\n* If the ``metaclass`` keyword argument is based with the bases, it is\n used.\n\n* Otherwise, if there is at least one base class, its metaclass is\n used.\n\n* Otherwise, the default metaclass (``type``) is used.\n\nThe potential uses for metaclasses are boundless. Some ideas that have\nbeen explored including logging, interface checking, automatic\ndelegation, automatic property creation, proxies, frameworks, and\nautomatic resource locking/synchronization.\n\nHere is an example of a metaclass that uses an\n``collections.OrderedDict`` to remember the order that class members\nwere defined:\n\n class OrderedClass(type):\n\n @classmethod\n def __prepare__(metacls, name, bases, **kwds):\n return collections.OrderedDict()\n\n def __new__(cls, name, bases, classdict):\n result = type.__new__(cls, name, bases, dict(classdict))\n result.members = tuple(classdict)\n return result\n\n class A(metaclass=OrderedClass):\n def one(self): pass\n def two(self): pass\n def three(self): pass\n def four(self): pass\n\n >>> A.members\n (\'__module__\', \'one\', \'two\', \'three\', \'four\')\n\nWhen the class definition for *A* gets executed, the process begins\nwith calling the metaclass\'s ``__prepare__()`` method which returns an\nempty ``collections.OrderedDict``. That mapping records the methods\nand attributes of *A* as they are defined within the body of the class\nstatement. Once those definitions are executed, the ordered dictionary\nis fully populated and the metaclass\'s ``__new__()`` method gets\ninvoked. That method builds the new type and it saves the ordered\ndictionary keys in an attribute called *members*.\n\n\nEmulating callable objects\n==========================\n\nobject.__call__(self[, args...])\n\n Called when the instance is "called" as a function; if this method\n is defined, ``x(arg1, arg2, ...)`` is a shorthand for\n ``x.__call__(arg1, arg2, ...)``.\n\n\nEmulating container types\n=========================\n\nThe following methods can be defined to implement container objects.\nContainers usually are sequences (such as lists or tuples) or mappings\n(like dictionaries), but can represent other containers as well. The\nfirst set of methods is used either to emulate a sequence or to\nemulate a mapping; the difference is that for a sequence, the\nallowable keys should be the integers *k* for which ``0 <= k < N``\nwhere *N* is the length of the sequence, or slice objects, which\ndefine a range of items. It is also recommended that mappings provide\nthe methods ``keys()``, ``values()``, ``items()``, ``get()``,\n``clear()``, ``setdefault()``, ``pop()``, ``popitem()``, ``copy()``,\nand ``update()`` behaving similar to those for Python\'s standard\ndictionary objects. The ``collections`` module provides a\n``MutableMapping`` abstract base class to help create those methods\nfrom a base set of ``__getitem__()``, ``__setitem__()``,\n``__delitem__()``, and ``keys()``. Mutable sequences should provide\nmethods ``append()``, ``count()``, ``index()``, ``extend()``,\n``insert()``, ``pop()``, ``remove()``, ``reverse()`` and ``sort()``,\nlike Python standard list objects. Finally, sequence types should\nimplement addition (meaning concatenation) and multiplication (meaning\nrepetition) by defining the methods ``__add__()``, ``__radd__()``,\n``__iadd__()``, ``__mul__()``, ``__rmul__()`` and ``__imul__()``\ndescribed below; they should not define other numerical operators. It\nis recommended that both mappings and sequences implement the\n``__contains__()`` method to allow efficient use of the ``in``\noperator; for mappings, ``in`` should search the mapping\'s keys; for\nsequences, it should search through the values. It is further\nrecommended that both mappings and sequences implement the\n``__iter__()`` method to allow efficient iteration through the\ncontainer; for mappings, ``__iter__()`` should be the same as\n``keys()``; for sequences, it should iterate through the values.\n\nobject.__len__(self)\n\n Called to implement the built-in function ``len()``. Should return\n the length of the object, an integer ``>=`` 0. Also, an object\n that doesn\'t define a ``__bool__()`` method and whose ``__len__()``\n method returns zero is considered to be false in a Boolean context.\n\nNote: Slicing is done exclusively with the following three methods. A\n call like\n\n a[1:2] = b\n\n is translated to\n\n a[slice(1, 2, None)] = b\n\n and so forth. Missing slice items are always filled in with\n ``None``.\n\nobject.__getitem__(self, key)\n\n Called to implement evaluation of ``self[key]``. For sequence\n types, the accepted keys should be integers and slice objects.\n Note that the special interpretation of negative indexes (if the\n class wishes to emulate a sequence type) is up to the\n ``__getitem__()`` method. If *key* is of an inappropriate type,\n ``TypeError`` may be raised; if of a value outside the set of\n indexes for the sequence (after any special interpretation of\n negative values), ``IndexError`` should be raised. For mapping\n types, if *key* is missing (not in the container), ``KeyError``\n should be raised.\n\n Note: ``for`` loops expect that an ``IndexError`` will be raised for\n illegal indexes to allow proper detection of the end of the\n sequence.\n\nobject.__setitem__(self, key, value)\n\n Called to implement assignment to ``self[key]``. Same note as for\n ``__getitem__()``. This should only be implemented for mappings if\n the objects support changes to the values for keys, or if new keys\n can be added, or for sequences if elements can be replaced. The\n same exceptions should be raised for improper *key* values as for\n the ``__getitem__()`` method.\n\nobject.__delitem__(self, key)\n\n Called to implement deletion of ``self[key]``. Same note as for\n ``__getitem__()``. This should only be implemented for mappings if\n the objects support removal of keys, or for sequences if elements\n can be removed from the sequence. The same exceptions should be\n raised for improper *key* values as for the ``__getitem__()``\n method.\n\nobject.__iter__(self)\n\n This method is called when an iterator is required for a container.\n This method should return a new iterator object that can iterate\n over all the objects in the container. For mappings, it should\n iterate over the keys of the container, and should also be made\n available as the method ``keys()``.\n\n Iterator objects also need to implement this method; they are\n required to return themselves. For more information on iterator\n objects, see *Iterator Types*.\n\nobject.__reversed__(self)\n\n Called (if present) by the ``reversed()`` builtin to implement\n reverse iteration. It should return a new iterator object that\n iterates over all the objects in the container in reverse order.\n\n If the ``__reversed__()`` method is not provided, the\n ``reversed()`` builtin will fall back to using the sequence\n protocol (``__len__()`` and ``__getitem__()``). Objects that\n support the sequence protocol should only provide\n ``__reversed__()`` if they can provide an implementation that is\n more efficient than the one provided by ``reversed()``.\n\nThe membership test operators (``in`` and ``not in``) are normally\nimplemented as an iteration through a sequence. However, container\nobjects can supply the following special method with a more efficient\nimplementation, which also does not require the object be a sequence.\n\nobject.__contains__(self, item)\n\n Called to implement membership test operators. Should return true\n if *item* is in *self*, false otherwise. For mapping objects, this\n should consider the keys of the mapping rather than the values or\n the key-item pairs.\n\n\nEmulating numeric types\n=======================\n\nThe following methods can be defined to emulate numeric objects.\nMethods corresponding to operations that are not supported by the\nparticular kind of number implemented (e.g., bitwise operations for\nnon-integral numbers) should be left undefined.\n\nobject.__add__(self, other)\nobject.__sub__(self, other)\nobject.__mul__(self, other)\nobject.__truediv__(self, other)\nobject.__floordiv__(self, other)\nobject.__mod__(self, other)\nobject.__divmod__(self, other)\nobject.__pow__(self, other[, modulo])\nobject.__lshift__(self, other)\nobject.__rshift__(self, other)\nobject.__and__(self, other)\nobject.__xor__(self, other)\nobject.__or__(self, other)\n\n These methods are called to implement the binary arithmetic\n operations (``+``, ``-``, ``*``, ``/``, ``//``, ``%``,\n ``divmod()``, ``pow()``, ``**``, ``<<``, ``>>``, ``&``, ``^``,\n ``|``). For instance, to evaluate the expression ``x + y``, where\n *x* is an instance of a class that has an ``__add__()`` method,\n ``x.__add__(y)`` is called. The ``__divmod__()`` method should be\n the equivalent to using ``__floordiv__()`` and ``__mod__()``; it\n should not be related to ``__truediv__()``. Note that\n ``__pow__()`` should be defined to accept an optional third\n argument if the ternary version of the built-in ``pow()`` function\n is to be supported.\n\n If one of those methods does not support the operation with the\n supplied arguments, it should return ``NotImplemented``.\n\nobject.__radd__(self, other)\nobject.__rsub__(self, other)\nobject.__rmul__(self, other)\nobject.__rtruediv__(self, other)\nobject.__rfloordiv__(self, other)\nobject.__rmod__(self, other)\nobject.__rdivmod__(self, other)\nobject.__rpow__(self, other)\nobject.__rlshift__(self, other)\nobject.__rrshift__(self, other)\nobject.__rand__(self, other)\nobject.__rxor__(self, other)\nobject.__ror__(self, other)\n\n These methods are called to implement the binary arithmetic\n operations (``+``, ``-``, ``*``, ``/``, ``//``, ``%``,\n ``divmod()``, ``pow()``, ``**``, ``<<``, ``>>``, ``&``, ``^``,\n ``|``) with reflected (swapped) operands. These functions are only\n called if the left operand does not support the corresponding\n operation and the operands are of different types. [3] For\n instance, to evaluate the expression ``x - y``, where *y* is an\n instance of a class that has an ``__rsub__()`` method,\n ``y.__rsub__(x)`` is called if ``x.__sub__(y)`` returns\n *NotImplemented*.\n\n Note that ternary ``pow()`` will not try calling ``__rpow__()``\n (the coercion rules would become too complicated).\n\n Note: If the right operand\'s type is a subclass of the left operand\'s\n type and that subclass provides the reflected method for the\n operation, this method will be called before the left operand\'s\n non-reflected method. This behavior allows subclasses to\n override their ancestors\' operations.\n\nobject.__iadd__(self, other)\nobject.__isub__(self, other)\nobject.__imul__(self, other)\nobject.__itruediv__(self, other)\nobject.__ifloordiv__(self, other)\nobject.__imod__(self, other)\nobject.__ipow__(self, other[, modulo])\nobject.__ilshift__(self, other)\nobject.__irshift__(self, other)\nobject.__iand__(self, other)\nobject.__ixor__(self, other)\nobject.__ior__(self, other)\n\n These methods are called to implement the augmented arithmetic\n assignments (``+=``, ``-=``, ``*=``, ``/=``, ``//=``, ``%=``,\n ``**=``, ``<<=``, ``>>=``, ``&=``, ``^=``, ``|=``). These methods\n should attempt to do the operation in-place (modifying *self*) and\n return the result (which could be, but does not have to be,\n *self*). If a specific method is not defined, the augmented\n assignment falls back to the normal methods. For instance, to\n execute the statement ``x += y``, where *x* is an instance of a\n class that has an ``__iadd__()`` method, ``x.__iadd__(y)`` is\n called. If *x* is an instance of a class that does not define a\n ``__iadd__()`` method, ``x.__add__(y)`` and ``y.__radd__(x)`` are\n considered, as with the evaluation of ``x + y``.\n\nobject.__neg__(self)\nobject.__pos__(self)\nobject.__abs__(self)\nobject.__invert__(self)\n\n Called to implement the unary arithmetic operations (``-``, ``+``,\n ``abs()`` and ``~``).\n\nobject.__complex__(self)\nobject.__int__(self)\nobject.__float__(self)\nobject.__round__(self[, n])\n\n Called to implement the built-in functions ``complex()``,\n ``int()``, ``float()`` and ``round()``. Should return a value of\n the appropriate type.\n\nobject.__index__(self)\n\n Called to implement ``operator.index()``. Also called whenever\n Python needs an integer object (such as in slicing, or in the\n built-in ``bin()``, ``hex()`` and ``oct()`` functions). Must return\n an integer.\n\n\nWith Statement Context Managers\n===============================\n\nA *context manager* is an object that defines the runtime context to\nbe established when executing a ``with`` statement. The context\nmanager handles the entry into, and the exit from, the desired runtime\ncontext for the execution of the block of code. Context managers are\nnormally invoked using the ``with`` statement (described in section\n*The with statement*), but can also be used by directly invoking their\nmethods.\n\nTypical uses of context managers include saving and restoring various\nkinds of global state, locking and unlocking resources, closing opened\nfiles, etc.\n\nFor more information on context managers, see *Context Manager Types*.\n\nobject.__enter__(self)\n\n Enter the runtime context related to this object. The ``with``\n statement will bind this method\'s return value to the target(s)\n specified in the ``as`` clause of the statement, if any.\n\nobject.__exit__(self, exc_type, exc_value, traceback)\n\n Exit the runtime context related to this object. The parameters\n describe the exception that caused the context to be exited. If the\n context was exited without an exception, all three arguments will\n be ``None``.\n\n If an exception is supplied, and the method wishes to suppress the\n exception (i.e., prevent it from being propagated), it should\n return a true value. Otherwise, the exception will be processed\n normally upon exit from this method.\n\n Note that ``__exit__()`` methods should not reraise the passed-in\n exception; this is the caller\'s responsibility.\n\nSee also:\n\n **PEP 0343** - The "with" statement\n The specification, background, and examples for the Python\n ``with`` statement.\n\n\nSpecial method lookup\n=====================\n\nFor custom classes, implicit invocations of special methods are only\nguaranteed to work correctly if defined on an object\'s type, not in\nthe object\'s instance dictionary. That behaviour is the reason why\nthe following code raises an exception:\n\n >>> class C(object):\n ... pass\n ...\n >>> c = C()\n >>> c.__len__ = lambda: 5\n >>> len(c)\n Traceback (most recent call last):\n File "", line 1, in \n TypeError: object of type \'C\' has no len()\n\nThe rationale behind this behaviour lies with a number of special\nmethods such as ``__hash__()`` and ``__repr__()`` that are implemented\nby all objects, including type objects. If the implicit lookup of\nthese methods used the conventional lookup process, they would fail\nwhen invoked on the type object itself:\n\n >>> 1 .__hash__() == hash(1)\n True\n >>> int.__hash__() == hash(int)\n Traceback (most recent call last):\n File "", line 1, in \n TypeError: descriptor \'__hash__\' of \'int\' object needs an argument\n\nIncorrectly attempting to invoke an unbound method of a class in this\nway is sometimes referred to as \'metaclass confusion\', and is avoided\nby bypassing the instance when looking up special methods:\n\n >>> type(1).__hash__(1) == hash(1)\n True\n >>> type(int).__hash__(int) == hash(int)\n True\n\nIn addition to bypassing any instance attributes in the interest of\ncorrectness, implicit special method lookup generally also bypasses\nthe ``__getattribute__()`` method even of the object\'s metaclass:\n\n >>> class Meta(type):\n ... def __getattribute__(*args):\n ... print("Metaclass getattribute invoked")\n ... return type.__getattribute__(*args)\n ...\n >>> class C(object, metaclass=Meta):\n ... def __len__(self):\n ... return 10\n ... def __getattribute__(*args):\n ... print("Class getattribute invoked")\n ... return object.__getattribute__(*args)\n ...\n >>> c = C()\n >>> c.__len__() # Explicit lookup via instance\n Class getattribute invoked\n 10\n >>> type(c).__len__(c) # Explicit lookup via type\n Metaclass getattribute invoked\n 10\n >>> len(c) # Implicit lookup\n 10\n\nBypassing the ``__getattribute__()`` machinery in this fashion\nprovides significant scope for speed optimisations within the\ninterpreter, at the cost of some flexibility in the handling of\nspecial methods (the special method *must* be set on the class object\nitself in order to be consistently invoked by the interpreter).\n\n-[ Footnotes ]-\n\n[1] It *is* possible in some cases to change an object\'s type, under\n certain controlled conditions. It generally isn\'t a good idea\n though, since it can lead to some very strange behaviour if it is\n handled incorrectly.\n\n[2] A descriptor can define any combination of ``__get__()``,\n ``__set__()`` and ``__delete__()``. If it does not define\n ``__get__()``, then accessing the attribute even on an instance\n will return the descriptor object itself. If the descriptor\n defines ``__set__()`` and/or ``__delete__()``, it is a data\n descriptor; if it defines neither, it is a non-data descriptor.\n\n[3] For operands of the same type, it is assumed that if the non-\n reflected method (such as ``__add__()``) fails the operation is\n not supported, which is why the reflected method is not called.\n', - 'string-methods': '\nString Methods\n**************\n\nString objects support the methods listed below. Note that none of\nthese methods take keyword arguments.\n\nIn addition, Python\'s strings support the sequence type methods\ndescribed in the *Sequence Types --- str, bytes, bytearray, list,\ntuple, range* section. To output formatted strings, see the *String\nFormatting* section. Also, see the ``re`` module for string functions\nbased on regular expressions.\n\nstr.capitalize()\n\n Return a copy of the string with only its first character\n capitalized.\n\nstr.center(width[, fillchar])\n\n Return centered in a string of length *width*. Padding is done\n using the specified *fillchar* (default is a space).\n\nstr.count(sub[, start[, end]])\n\n Return the number of non-overlapping occurrences of substring *sub*\n in the range [*start*, *end*]. Optional arguments *start* and\n *end* are interpreted as in slice notation.\n\nstr.encode([encoding[, errors]])\n\n Return an encoded version of the string as a bytes object. Default\n encoding is the current default string encoding. *errors* may be\n given to set a different error handling scheme. The default for\n *errors* is ``\'strict\'``, meaning that encoding errors raise a\n ``UnicodeError``. Other possible values are ``\'ignore\'``,\n ``\'replace\'``, ``\'xmlcharrefreplace\'``, ``\'backslashreplace\'`` and\n any other name registered via ``codecs.register_error()``, see\n section *Codec Base Classes*. For a list of possible encodings, see\n section *Standard Encodings*.\n\nstr.endswith(suffix[, start[, end]])\n\n Return ``True`` if the string ends with the specified *suffix*,\n otherwise return ``False``. *suffix* can also be a tuple of\n suffixes to look for. With optional *start*, test beginning at\n that position. With optional *end*, stop comparing at that\n position.\n\nstr.expandtabs([tabsize])\n\n Return a copy of the string where all tab characters are replaced\n by one or more spaces, depending on the current column and the\n given tab size. The column number is reset to zero after each\n newline occurring in the string. If *tabsize* is not given, a tab\n size of ``8`` characters is assumed. This doesn\'t understand other\n non-printing characters or escape sequences.\n\nstr.find(sub[, start[, end]])\n\n Return the lowest index in the string where substring *sub* is\n found, such that *sub* is contained in the range [*start*, *end*].\n Optional arguments *start* and *end* are interpreted as in slice\n notation. Return ``-1`` if *sub* is not found.\n\nstr.format(*args, **kwargs)\n\n Perform a string formatting operation. The *format_string*\n argument can contain literal text or replacement fields delimited\n by braces ``{}``. Each replacement field contains either the\n numeric index of a positional argument, or the name of a keyword\n argument. Returns a copy of *format_string* where each replacement\n field is replaced with the string value of the corresponding\n argument.\n\n >>> "The sum of 1 + 2 is {0}".format(1+2)\n \'The sum of 1 + 2 is 3\'\n\n See *Format String Syntax* for a description of the various\n formatting options that can be specified in format strings.\n\nstr.index(sub[, start[, end]])\n\n Like ``find()``, but raise ``ValueError`` when the substring is not\n found.\n\nstr.isalnum()\n\n Return true if all characters in the string are alphanumeric and\n there is at least one character, false otherwise.\n\nstr.isalpha()\n\n Return true if all characters in the string are alphabetic and\n there is at least one character, false otherwise.\n\nstr.isdecimal()\n\n Return true if all characters in the string are decimal characters\n and there is at least one character, false otherwise. Decimal\n characters include digit characters, and all characters that that\n can be used to form decimal-radix numbers, e.g. U+0660, ARABIC-\n INDIC DIGIT ZERO.\n\nstr.isdigit()\n\n Return true if all characters in the string are digits and there is\n at least one character, false otherwise.\n\nstr.isidentifier()\n\n Return true if the string is a valid identifier according to the\n language definition, section *Identifiers and keywords*.\n\nstr.islower()\n\n Return true if all cased characters in the string are lowercase and\n there is at least one cased character, false otherwise.\n\nstr.isnumeric()\n\n Return true if all characters in the string are numeric characters,\n and there is at least one character, false otherwise. Numeric\n characters include digit characters, and all characters that have\n the Unicode numeric value property, e.g. U+2155, VULGAR FRACTION\n ONE FIFTH.\n\nstr.isprintable()\n\n Return true if all characters in the string are printable or the\n string is empty, false otherwise. Nonprintable characters are\n those characters defined in the Unicode character database as\n "Other" or "Separator", excepting the ASCII space (0x20) which is\n considered printable. (Note that printable characters in this\n context are those which should not be escaped when ``repr()`` is\n invoked on a string. It has no bearing on the handling of strings\n written to ``sys.stdout`` or ``sys.stderr``.)\n\nstr.isspace()\n\n Return true if there are only whitespace characters in the string\n and there is at least one character, false otherwise.\n\nstr.istitle()\n\n Return true if the string is a titlecased string and there is at\n least one character, for example uppercase characters may only\n follow uncased characters and lowercase characters only cased ones.\n Return false otherwise.\n\nstr.isupper()\n\n Return true if all cased characters in the string are uppercase and\n there is at least one cased character, false otherwise.\n\nstr.join(seq)\n\n Return a string which is the concatenation of the strings in the\n sequence *seq*. A ``TypeError`` will be raised if there are any\n non-string values in *seq*, including ``bytes`` objects. The\n separator between elements is the string providing this method.\n\nstr.ljust(width[, fillchar])\n\n Return the string left justified in a string of length *width*.\n Padding is done using the specified *fillchar* (default is a\n space). The original string is returned if *width* is less than\n ``len(s)``.\n\nstr.lower()\n\n Return a copy of the string converted to lowercase.\n\nstr.lstrip([chars])\n\n Return a copy of the string with leading characters removed. The\n *chars* argument is a string specifying the set of characters to be\n removed. If omitted or ``None``, the *chars* argument defaults to\n removing whitespace. The *chars* argument is not a prefix; rather,\n all combinations of its values are stripped:\n\n >>> \' spacious \'.lstrip()\n \'spacious \'\n >>> \'www.example.com\'.lstrip(\'cmowz.\')\n \'example.com\'\n\nstatic str.maketrans(x[, y[, z]])\n\n This static method returns a translation table usable for\n ``str.translate()``.\n\n If there is only one argument, it must be a dictionary mapping\n Unicode ordinals (integers) or characters (strings of length 1) to\n Unicode ordinals, strings (of arbitrary lengths) or None.\n Character keys will then be converted to ordinals.\n\n If there are two arguments, they must be strings of equal length,\n and in the resulting dictionary, each character in x will be mapped\n to the character at the same position in y. If there is a third\n argument, it must be a string, whose characters will be mapped to\n None in the result.\n\nstr.partition(sep)\n\n Split the string at the first occurrence of *sep*, and return a\n 3-tuple containing the part before the separator, the separator\n itself, and the part after the separator. If the separator is not\n found, return a 3-tuple containing the string itself, followed by\n two empty strings.\n\nstr.replace(old, new[, count])\n\n Return a copy of the string with all occurrences of substring *old*\n replaced by *new*. If the optional argument *count* is given, only\n the first *count* occurrences are replaced.\n\nstr.rfind(sub[, start[, end]])\n\n Return the highest index in the string where substring *sub* is\n found, such that *sub* is contained within s[start,end]. Optional\n arguments *start* and *end* are interpreted as in slice notation.\n Return ``-1`` on failure.\n\nstr.rindex(sub[, start[, end]])\n\n Like ``rfind()`` but raises ``ValueError`` when the substring *sub*\n is not found.\n\nstr.rjust(width[, fillchar])\n\n Return the string right justified in a string of length *width*.\n Padding is done using the specified *fillchar* (default is a\n space). The original string is returned if *width* is less than\n ``len(s)``.\n\nstr.rpartition(sep)\n\n Split the string at the last occurrence of *sep*, and return a\n 3-tuple containing the part before the separator, the separator\n itself, and the part after the separator. If the separator is not\n found, return a 3-tuple containing two empty strings, followed by\n the string itself.\n\nstr.rsplit([sep[, maxsplit]])\n\n Return a list of the words in the string, using *sep* as the\n delimiter string. If *maxsplit* is given, at most *maxsplit* splits\n are done, the *rightmost* ones. If *sep* is not specified or\n ``None``, any whitespace string is a separator. Except for\n splitting from the right, ``rsplit()`` behaves like ``split()``\n which is described in detail below.\n\nstr.rstrip([chars])\n\n Return a copy of the string with trailing characters removed. The\n *chars* argument is a string specifying the set of characters to be\n removed. If omitted or ``None``, the *chars* argument defaults to\n removing whitespace. The *chars* argument is not a suffix; rather,\n all combinations of its values are stripped:\n\n >>> \' spacious \'.rstrip()\n \' spacious\'\n >>> \'mississippi\'.rstrip(\'ipz\')\n \'mississ\'\n\nstr.split([sep[, maxsplit]])\n\n Return a list of the words in the string, using *sep* as the\n delimiter string. If *maxsplit* is given, at most *maxsplit*\n splits are done (thus, the list will have at most ``maxsplit+1``\n elements). If *maxsplit* is not specified, then there is no limit\n on the number of splits (all possible splits are made).\n\n If *sep* is given, consecutive delimiters are not grouped together\n and are deemed to delimit empty strings (for example,\n ``\'1,,2\'.split(\',\')`` returns ``[\'1\', \'\', \'2\']``). The *sep*\n argument may consist of multiple characters (for example,\n ``\'1<>2<>3\'.split(\'<>\')`` returns ``[\'1\', \'2\', \'3\']``). Splitting\n an empty string with a specified separator returns ``[\'\']``.\n\n If *sep* is not specified or is ``None``, a different splitting\n algorithm is applied: runs of consecutive whitespace are regarded\n as a single separator, and the result will contain no empty strings\n at the start or end if the string has leading or trailing\n whitespace. Consequently, splitting an empty string or a string\n consisting of just whitespace with a ``None`` separator returns\n ``[]``.\n\n For example, ``\' 1 2 3 \'.split()`` returns ``[\'1\', \'2\', \'3\']``,\n and ``\' 1 2 3 \'.split(None, 1)`` returns ``[\'1\', \'2 3 \']``.\n\nstr.splitlines([keepends])\n\n Return a list of the lines in the string, breaking at line\n boundaries. Line breaks are not included in the resulting list\n unless *keepends* is given and true.\n\nstr.startswith(prefix[, start[, end]])\n\n Return ``True`` if string starts with the *prefix*, otherwise\n return ``False``. *prefix* can also be a tuple of prefixes to look\n for. With optional *start*, test string beginning at that\n position. With optional *end*, stop comparing string at that\n position.\n\nstr.strip([chars])\n\n Return a copy of the string with the leading and trailing\n characters removed. The *chars* argument is a string specifying the\n set of characters to be removed. If omitted or ``None``, the\n *chars* argument defaults to removing whitespace. The *chars*\n argument is not a prefix or suffix; rather, all combinations of its\n values are stripped:\n\n >>> \' spacious \'.strip()\n \'spacious\'\n >>> \'www.example.com\'.strip(\'cmowz.\')\n \'example\'\n\nstr.swapcase()\n\n Return a copy of the string with uppercase characters converted to\n lowercase and vice versa.\n\nstr.title()\n\n Return a titlecased version of the string: words start with\n uppercase characters, all remaining cased characters are lowercase.\n\nstr.translate(map)\n\n Return a copy of the *s* where all characters have been mapped\n through the *map* which must be a dictionary of Unicode ordinals\n (integers) to Unicode ordinals, strings or ``None``. Unmapped\n characters are left untouched. Characters mapped to ``None`` are\n deleted.\n\n You can use ``str.maketrans()`` to create a translation map from\n character-to-character mappings in different formats.\n\n Note: An even more flexible approach is to create a custom character\n mapping codec using the ``codecs`` module (see\n ``encodings.cp1251`` for an example).\n\nstr.upper()\n\n Return a copy of the string converted to uppercase.\n\nstr.zfill(width)\n\n Return the numeric string left filled with zeros in a string of\n length *width*. A sign prefix is handled correctly. The original\n string is returned if *width* is less than ``len(s)``.\n', - 'strings': '\nString and Bytes literals\n*************************\n\nString literals are described by the following lexical definitions:\n\n stringliteral ::= [stringprefix](shortstring | longstring)\n stringprefix ::= "r" | "R"\n shortstring ::= "\'" shortstringitem* "\'" | \'"\' shortstringitem* \'"\'\n longstring ::= "\'\'\'" longstringitem* "\'\'\'" | \'"""\' longstringitem* \'"""\'\n shortstringitem ::= shortstringchar | stringescapeseq\n longstringitem ::= longstringchar | stringescapeseq\n shortstringchar ::= \n longstringchar ::= \n stringescapeseq ::= "\\" \n\n bytesliteral ::= bytesprefix(shortbytes | longbytes)\n bytesprefix ::= "b" | "B"\n shortbytes ::= "\'" shortbytesitem* "\'" | \'"\' shortbytesitem* \'"\'\n longbytes ::= "\'\'\'" longbytesitem* "\'\'\'" | \'"""\' longbytesitem* \'"""\'\n shortbytesitem ::= shortbyteschar | bytesescapeseq\n longbytesitem ::= longbyteschar | bytesescapeseq\n shortbyteschar ::= \n longbyteschar ::= \n bytesescapeseq ::= "\\" \n\nOne syntactic restriction not indicated by these productions is that\nwhitespace is not allowed between the **stringprefix** or\n**bytesprefix** and the rest of the literal. The source character set\nis defined by the encoding declaration; it is UTF-8 if no encoding\ndeclaration is given in the source file; see section *Encoding\ndeclarations*.\n\nIn plain English: Both types of literals can be enclosed in matching\nsingle quotes (``\'``) or double quotes (``"``). They can also be\nenclosed in matching groups of three single or double quotes (these\nare generally referred to as *triple-quoted strings*). The backslash\n(``\\``) character is used to escape characters that otherwise have a\nspecial meaning, such as newline, backslash itself, or the quote\ncharacter.\n\nString literals may optionally be prefixed with a letter ``\'r\'`` or\n``\'R\'``; such strings are called *raw strings* and treat backslashes\nas literal characters. As a result, ``\'\\U\'`` and ``\'\\u\'`` escapes in\nraw strings are not treated specially.\n\nBytes literals are always prefixed with ``\'b\'`` or ``\'B\'``; they\nproduce an instance of the ``bytes`` type instead of the ``str`` type.\nThey may only contain ASCII characters; bytes with a numeric value of\n128 or greater must be expressed with escapes.\n\nIn triple-quoted strings, unescaped newlines and quotes are allowed\n(and are retained), except that three unescaped quotes in a row\nterminate the string. (A "quote" is the character used to open the\nstring, i.e. either ``\'`` or ``"``.)\n\nUnless an ``\'r\'`` or ``\'R\'`` prefix is present, escape sequences in\nstrings are interpreted according to rules similar to those used by\nStandard C. The recognized escape sequences are:\n\n+-------------------+-----------------------------------+---------+\n| Escape Sequence | Meaning | Notes |\n+===================+===================================+=========+\n| ``\\newline`` | Backslash and newline ignored | |\n+-------------------+-----------------------------------+---------+\n| ``\\\\`` | Backslash (``\\``) | |\n+-------------------+-----------------------------------+---------+\n| ``\\\'`` | Single quote (``\'``) | |\n+-------------------+-----------------------------------+---------+\n| ``\\"`` | Double quote (``"``) | |\n+-------------------+-----------------------------------+---------+\n| ``\\a`` | ASCII Bell (BEL) | |\n+-------------------+-----------------------------------+---------+\n| ``\\b`` | ASCII Backspace (BS) | |\n+-------------------+-----------------------------------+---------+\n| ``\\f`` | ASCII Formfeed (FF) | |\n+-------------------+-----------------------------------+---------+\n| ``\\n`` | ASCII Linefeed (LF) | |\n+-------------------+-----------------------------------+---------+\n| ``\\r`` | ASCII Carriage Return (CR) | |\n+-------------------+-----------------------------------+---------+\n| ``\\t`` | ASCII Horizontal Tab (TAB) | |\n+-------------------+-----------------------------------+---------+\n| ``\\v`` | ASCII Vertical Tab (VT) | |\n+-------------------+-----------------------------------+---------+\n| ``\\ooo`` | Character with octal value *ooo* | (1,3) |\n+-------------------+-----------------------------------+---------+\n| ``\\xhh`` | Character with hex value *hh* | (2,3) |\n+-------------------+-----------------------------------+---------+\n\nEscape sequences only recognized in string literals are:\n\n+-------------------+-----------------------------------+---------+\n| Escape Sequence | Meaning | Notes |\n+===================+===================================+=========+\n| ``\\N{name}`` | Character named *name* in the | |\n| | Unicode database | |\n+-------------------+-----------------------------------+---------+\n| ``\\uxxxx`` | Character with 16-bit hex value | (4) |\n| | *xxxx* | |\n+-------------------+-----------------------------------+---------+\n| ``\\Uxxxxxxxx`` | Character with 32-bit hex value | (5) |\n| | *xxxxxxxx* | |\n+-------------------+-----------------------------------+---------+\n\nNotes:\n\n1. As in Standard C, up to three octal digits are accepted.\n\n2. Unlike in Standard C, at most two hex digits are accepted.\n\n3. In a bytes literal, hexadecimal and octal escapes denote the byte\n with the given value. In a string literal, these escapes denote a\n Unicode character with the given value.\n\n4. Individual code units which form parts of a surrogate pair can be\n encoded using this escape sequence. Unlike in Standard C, exactly\n two hex digits are required.\n\n5. Any Unicode character can be encoded this way, but characters\n outside the Basic Multilingual Plane (BMP) will be encoded using a\n surrogate pair if Python is compiled to use 16-bit code units (the\n default). Individual code units which form parts of a surrogate\n pair can be encoded using this escape sequence.\n\nUnlike Standard C, all unrecognized escape sequences are left in the\nstring unchanged, i.e., *the backslash is left in the string*. (This\nbehavior is useful when debugging: if an escape sequence is mistyped,\nthe resulting output is more easily recognized as broken.) It is also\nimportant to note that the escape sequences only recognized in string\nliterals fall into the category of unrecognized escapes for bytes\nliterals.\n\nEven in a raw string, string quotes can be escaped with a backslash,\nbut the backslash remains in the string; for example, ``r"\\""`` is a\nvalid string literal consisting of two characters: a backslash and a\ndouble quote; ``r"\\"`` is not a valid string literal (even a raw\nstring cannot end in an odd number of backslashes). Specifically, *a\nraw string cannot end in a single backslash* (since the backslash\nwould escape the following quote character). Note also that a single\nbackslash followed by a newline is interpreted as those two characters\nas part of the string, *not* as a line continuation.\n', - 'subscriptions': '\nSubscriptions\n*************\n\nA subscription selects an item of a sequence (string, tuple or list)\nor mapping (dictionary) object:\n\n subscription ::= primary "[" expression_list "]"\n\nThe primary must evaluate to an object that supports subscription,\ne.g. a list or dictionary. User-defined objects can support\nsubscription by defining a ``__getitem__()`` method.\n\nFor built-in objects, there are two types of objects that support\nsubscription:\n\nIf the primary is a mapping, the expression list must evaluate to an\nobject whose value is one of the keys of the mapping, and the\nsubscription selects the value in the mapping that corresponds to that\nkey. (The expression list is a tuple except if it has exactly one\nitem.)\n\nIf the primary is a sequence, the expression (list) must evaluate to\nan integer. If this value is negative, the length of the sequence is\nadded to it (so that, e.g., ``x[-1]`` selects the last item of ``x``.)\nThe resulting value must be a nonnegative integer less than the number\nof items in the sequence, and the subscription selects the item whose\nindex is that value (counting from zero).\n\nA string\'s items are characters. A character is not a separate data\ntype but a string of exactly one character.\n', + 'specialattrs': "\nSpecial Attributes\n******************\n\nThe implementation adds a few special read-only attributes to several\nobject types, where they are relevant. Some of these are not reported\nby the ``dir()`` built-in function.\n\nobject.__dict__\n\n A dictionary or other mapping object used to store an object's\n (writable) attributes.\n\ninstance.__class__\n\n The class to which a class instance belongs.\n\nclass.__bases__\n\n The tuple of base classes of a class object.\n\nclass.__name__\n\n The name of the class or type.\n\nThe following attributes are only supported by *new-style class*es.\n\nclass.__mro__\n\n This attribute is a tuple of classes that are considered when\n looking for base classes during method resolution.\n\nclass.mro()\n\n This method can be overridden by a metaclass to customize the\n method resolution order for its instances. It is called at class\n instantiation, and its result is stored in ``__mro__``.\n\nclass.__subclasses__()\n\n Each new-style class keeps a list of weak references to its\n immediate subclasses. This method returns a list of all those\n references still alive. Example:\n\n >>> int.__subclasses__()\n []\n\n-[ Footnotes ]-\n\n[1] Additional information on these special methods may be found in\n the Python Reference Manual (*Basic customization*).\n\n[2] As a consequence, the list ``[1, 2]`` is considered equal to\n ``[1.0, 2.0]``, and similarly for tuples.\n\n[3] They must have since the parser can't tell the type of the\n operands.\n\n[4] To format only a tuple you should therefore provide a singleton\n tuple whose only element is the tuple to be formatted.\n", + 'specialnames': '\nSpecial method names\n********************\n\nA class can implement certain operations that are invoked by special\nsyntax (such as arithmetic operations or subscripting and slicing) by\ndefining methods with special names. This is Python\'s approach to\n*operator overloading*, allowing classes to define their own behavior\nwith respect to language operators. For instance, if a class defines\na method named ``__getitem__()``, and ``x`` is an instance of this\nclass, then ``x[i]`` is roughly equivalent to ``type(x).__getitem__(x,\ni)``. Except where mentioned, attempts to execute an operation raise\nan exception when no appropriate method is defined (typically\n``AttributeError`` or ``TypeError``).\n\nWhen implementing a class that emulates any built-in type, it is\nimportant that the emulation only be implemented to the degree that it\nmakes sense for the object being modelled. For example, some\nsequences may work well with retrieval of individual elements, but\nextracting a slice may not make sense. (One example of this is the\n``NodeList`` interface in the W3C\'s Document Object Model.)\n\n\nBasic customization\n===================\n\nobject.__new__(cls[, ...])\n\n Called to create a new instance of class *cls*. ``__new__()`` is a\n static method (special-cased so you need not declare it as such)\n that takes the class of which an instance was requested as its\n first argument. The remaining arguments are those passed to the\n object constructor expression (the call to the class). The return\n value of ``__new__()`` should be the new object instance (usually\n an instance of *cls*).\n\n Typical implementations create a new instance of the class by\n invoking the superclass\'s ``__new__()`` method using\n ``super(currentclass, cls).__new__(cls[, ...])`` with appropriate\n arguments and then modifying the newly-created instance as\n necessary before returning it.\n\n If ``__new__()`` returns an instance of *cls*, then the new\n instance\'s ``__init__()`` method will be invoked like\n ``__init__(self[, ...])``, where *self* is the new instance and the\n remaining arguments are the same as were passed to ``__new__()``.\n\n If ``__new__()`` does not return an instance of *cls*, then the new\n instance\'s ``__init__()`` method will not be invoked.\n\n ``__new__()`` is intended mainly to allow subclasses of immutable\n types (like int, str, or tuple) to customize instance creation. It\n is also commonly overridden in custom metaclasses in order to\n customize class creation.\n\nobject.__init__(self[, ...])\n\n Called when the instance is created. The arguments are those\n passed to the class constructor expression. If a base class has an\n ``__init__()`` method, the derived class\'s ``__init__()`` method,\n if any, must explicitly call it to ensure proper initialization of\n the base class part of the instance; for example:\n ``BaseClass.__init__(self, [args...])``. As a special constraint\n on constructors, no value may be returned; doing so will cause a\n ``TypeError`` to be raised at runtime.\n\nobject.__del__(self)\n\n Called when the instance is about to be destroyed. This is also\n called a destructor. If a base class has a ``__del__()`` method,\n the derived class\'s ``__del__()`` method, if any, must explicitly\n call it to ensure proper deletion of the base class part of the\n instance. Note that it is possible (though not recommended!) for\n the ``__del__()`` method to postpone destruction of the instance by\n creating a new reference to it. It may then be called at a later\n time when this new reference is deleted. It is not guaranteed that\n ``__del__()`` methods are called for objects that still exist when\n the interpreter exits.\n\n Note: ``del x`` doesn\'t directly call ``x.__del__()`` --- the former\n decrements the reference count for ``x`` by one, and the latter\n is only called when ``x``\'s reference count reaches zero. Some\n common situations that may prevent the reference count of an\n object from going to zero include: circular references between\n objects (e.g., a doubly-linked list or a tree data structure with\n parent and child pointers); a reference to the object on the\n stack frame of a function that caught an exception (the traceback\n stored in ``sys.exc_info()[2]`` keeps the stack frame alive); or\n a reference to the object on the stack frame that raised an\n unhandled exception in interactive mode (the traceback stored in\n ``sys.last_traceback`` keeps the stack frame alive). The first\n situation can only be remedied by explicitly breaking the cycles;\n the latter two situations can be resolved by storing ``None`` in\n ``sys.last_traceback``. Circular references which are garbage are\n detected when the option cycle detector is enabled (it\'s on by\n default), but can only be cleaned up if there are no Python-\n level ``__del__()`` methods involved. Refer to the documentation\n for the ``gc`` module for more information about how\n ``__del__()`` methods are handled by the cycle detector,\n particularly the description of the ``garbage`` value.\n\n Warning: Due to the precarious circumstances under which ``__del__()``\n methods are invoked, exceptions that occur during their execution\n are ignored, and a warning is printed to ``sys.stderr`` instead.\n Also, when ``__del__()`` is invoked in response to a module being\n deleted (e.g., when execution of the program is done), other\n globals referenced by the ``__del__()`` method may already have\n been deleted or in the process of being torn down (e.g. the\n import machinery shutting down). For this reason, ``__del__()``\n methods should do the absolute minimum needed to maintain\n external invariants. Starting with version 1.5, Python\n guarantees that globals whose name begins with a single\n underscore are deleted from their module before other globals are\n deleted; if no other references to such globals exist, this may\n help in assuring that imported modules are still available at the\n time when the ``__del__()`` method is called.\n\nobject.__repr__(self)\n\n Called by the ``repr()`` built-in function to compute the\n "official" string representation of an object. If at all possible,\n this should look like a valid Python expression that could be used\n to recreate an object with the same value (given an appropriate\n environment). If this is not possible, a string of the form\n ``<...some useful description...>`` should be returned. The return\n value must be a string object. If a class defines ``__repr__()``\n but not ``__str__()``, then ``__repr__()`` is also used when an\n "informal" string representation of instances of that class is\n required.\n\n This is typically used for debugging, so it is important that the\n representation is information-rich and unambiguous.\n\nobject.__str__(self)\n\n Called by the ``str()`` built-in function and by the ``print()``\n function to compute the "informal" string representation of an\n object. This differs from ``__repr__()`` in that it does not have\n to be a valid Python expression: a more convenient or concise\n representation may be used instead. The return value must be a\n string object.\n\nobject.__format__(self, format_spec)\n\n Called by the ``format()`` built-in function (and by extension, the\n ``format()`` method of class ``str``) to produce a "formatted"\n string representation of an object. The ``format_spec`` argument is\n a string that contains a description of the formatting options\n desired. The interpretation of the ``format_spec`` argument is up\n to the type implementing ``__format__()``, however most classes\n will either delegate formatting to one of the built-in types, or\n use a similar formatting option syntax.\n\n See *Format Specification Mini-Language* for a description of the\n standard formatting syntax.\n\n The return value must be a string object.\n\nobject.__lt__(self, other)\nobject.__le__(self, other)\nobject.__eq__(self, other)\nobject.__ne__(self, other)\nobject.__gt__(self, other)\nobject.__ge__(self, other)\n\n These are the so-called "rich comparison" methods. The\n correspondence between operator symbols and method names is as\n follows: ``xy`` calls ``x.__gt__(y)``, and ``x>=y`` calls\n ``x.__ge__(y)``.\n\n A rich comparison method may return the singleton\n ``NotImplemented`` if it does not implement the operation for a\n given pair of arguments. By convention, ``False`` and ``True`` are\n returned for a successful comparison. However, these methods can\n return any value, so if the comparison operator is used in a\n Boolean context (e.g., in the condition of an ``if`` statement),\n Python will call ``bool()`` on the value to determine if the result\n is true or false.\n\n There are no implied relationships among the comparison operators.\n The truth of ``x==y`` does not imply that ``x!=y`` is false.\n Accordingly, when defining ``__eq__()``, one should also define\n ``__ne__()`` so that the operators will behave as expected. See\n the paragraph on ``__hash__()`` for some important notes on\n creating *hashable* objects which support custom comparison\n operations and are usable as dictionary keys.\n\n There are no swapped-argument versions of these methods (to be used\n when the left argument does not support the operation but the right\n argument does); rather, ``__lt__()`` and ``__gt__()`` are each\n other\'s reflection, ``__le__()`` and ``__ge__()`` are each other\'s\n reflection, and ``__eq__()`` and ``__ne__()`` are their own\n reflection.\n\n Arguments to rich comparison methods are never coerced.\n\n To automatically generate ordering operations from a single root\n operation, see the Total Ordering recipe in the ASPN cookbook.\n\nobject.__hash__(self)\n\n Called by built-in function ``hash()`` and for operations on\n members of hashed collections including ``set``, ``frozenset``, and\n ``dict``. ``__hash__()`` should return an integer. The only\n required property is that objects which compare equal have the same\n hash value; it is advised to somehow mix together (e.g. using\n exclusive or) the hash values for the components of the object that\n also play a part in comparison of objects.\n\n If a class does not define an ``__eq__()`` method it should not\n define a ``__hash__()`` operation either; if it defines\n ``__eq__()`` but not ``__hash__()``, its instances will not be\n usable as items in hashable collections. If a class defines\n mutable objects and implements an ``__eq__()`` method, it should\n not implement ``__hash__()``, since the implementation of hashable\n collections requires that a key\'s hash value is immutable (if the\n object\'s hash value changes, it will be in the wrong hash bucket).\n\n User-defined classes have ``__eq__()`` and ``__hash__()`` methods\n by default; with them, all objects compare unequal (except with\n themselves) and ``x.__hash__()`` returns ``id(x)``.\n\n Classes which inherit a ``__hash__()`` method from a parent class\n but change the meaning of ``__eq__()`` such that the hash value\n returned is no longer appropriate (e.g. by switching to a value-\n based concept of equality instead of the default identity based\n equality) can explicitly flag themselves as being unhashable by\n setting ``__hash__ = None`` in the class definition. Doing so means\n that not only will instances of the class raise an appropriate\n ``TypeError`` when a program attempts to retrieve their hash value,\n but they will also be correctly identified as unhashable when\n checking ``isinstance(obj, collections.Hashable)`` (unlike classes\n which define their own ``__hash__()`` to explicitly raise\n ``TypeError``).\n\n If a class that overrides ``__eq__()`` needs to retain the\n implementation of ``__hash__()`` from a parent class, the\n interpreter must be told this explicitly by setting ``__hash__ =\n .__hash__``. Otherwise the inheritance of\n ``__hash__()`` will be blocked, just as if ``__hash__`` had been\n explicitly set to ``None``.\n\nobject.__bool__(self)\n\n Called to implement truth value testing and the built-in operation\n ``bool()``; should return ``False`` or ``True``. When this method\n is not defined, ``__len__()`` is called, if it is defined, and the\n object is considered true if its result is nonzero. If a class\n defines neither ``__len__()`` nor ``__bool__()``, all its instances\n are considered true.\n\n\nCustomizing attribute access\n============================\n\nThe following methods can be defined to customize the meaning of\nattribute access (use of, assignment to, or deletion of ``x.name``)\nfor class instances.\n\nobject.__getattr__(self, name)\n\n Called when an attribute lookup has not found the attribute in the\n usual places (i.e. it is not an instance attribute nor is it found\n in the class tree for ``self``). ``name`` is the attribute name.\n This method should return the (computed) attribute value or raise\n an ``AttributeError`` exception.\n\n Note that if the attribute is found through the normal mechanism,\n ``__getattr__()`` is not called. (This is an intentional asymmetry\n between ``__getattr__()`` and ``__setattr__()``.) This is done both\n for efficiency reasons and because otherwise ``__getattr__()``\n would have no way to access other attributes of the instance. Note\n that at least for instance variables, you can fake total control by\n not inserting any values in the instance attribute dictionary (but\n instead inserting them in another object). See the\n ``__getattribute__()`` method below for a way to actually get total\n control over attribute access.\n\nobject.__getattribute__(self, name)\n\n Called unconditionally to implement attribute accesses for\n instances of the class. If the class also defines\n ``__getattr__()``, the latter will not be called unless\n ``__getattribute__()`` either calls it explicitly or raises an\n ``AttributeError``. This method should return the (computed)\n attribute value or raise an ``AttributeError`` exception. In order\n to avoid infinite recursion in this method, its implementation\n should always call the base class method with the same name to\n access any attributes it needs, for example,\n ``object.__getattribute__(self, name)``.\n\n Note: This method may still be bypassed when looking up special methods\n as the result of implicit invocation via language syntax or\n built-in functions. See *Special method lookup*.\n\nobject.__setattr__(self, name, value)\n\n Called when an attribute assignment is attempted. This is called\n instead of the normal mechanism (i.e. store the value in the\n instance dictionary). *name* is the attribute name, *value* is the\n value to be assigned to it.\n\n If ``__setattr__()`` wants to assign to an instance attribute, it\n should call the base class method with the same name, for example,\n ``object.__setattr__(self, name, value)``.\n\nobject.__delattr__(self, name)\n\n Like ``__setattr__()`` but for attribute deletion instead of\n assignment. This should only be implemented if ``del obj.name`` is\n meaningful for the object.\n\nobject.__dir__(self)\n\n Called when ``dir()`` is called on the object. A list must be\n returned.\n\n\nImplementing Descriptors\n------------------------\n\nThe following methods only apply when an instance of the class\ncontaining the method (a so-called *descriptor* class) appears in an\n*owner* class (the descriptor must be in either the owner\'s class\ndictionary or in the class dictionary for one of its parents). In the\nexamples below, "the attribute" refers to the attribute whose name is\nthe key of the property in the owner class\' ``__dict__``.\n\nobject.__get__(self, instance, owner)\n\n Called to get the attribute of the owner class (class attribute\n access) or of an instance of that class (instance attribute\n access). *owner* is always the owner class, while *instance* is the\n instance that the attribute was accessed through, or ``None`` when\n the attribute is accessed through the *owner*. This method should\n return the (computed) attribute value or raise an\n ``AttributeError`` exception.\n\nobject.__set__(self, instance, value)\n\n Called to set the attribute on an instance *instance* of the owner\n class to a new value, *value*.\n\nobject.__delete__(self, instance)\n\n Called to delete the attribute on an instance *instance* of the\n owner class.\n\n\nInvoking Descriptors\n--------------------\n\nIn general, a descriptor is an object attribute with "binding\nbehavior", one whose attribute access has been overridden by methods\nin the descriptor protocol: ``__get__()``, ``__set__()``, and\n``__delete__()``. If any of those methods are defined for an object,\nit is said to be a descriptor.\n\nThe default behavior for attribute access is to get, set, or delete\nthe attribute from an object\'s dictionary. For instance, ``a.x`` has a\nlookup chain starting with ``a.__dict__[\'x\']``, then\n``type(a).__dict__[\'x\']``, and continuing through the base classes of\n``type(a)`` excluding metaclasses.\n\nHowever, if the looked-up value is an object defining one of the\ndescriptor methods, then Python may override the default behavior and\ninvoke the descriptor method instead. Where this occurs in the\nprecedence chain depends on which descriptor methods were defined and\nhow they were called.\n\nThe starting point for descriptor invocation is a binding, ``a.x``.\nHow the arguments are assembled depends on ``a``:\n\nDirect Call\n The simplest and least common call is when user code directly\n invokes a descriptor method: ``x.__get__(a)``.\n\nInstance Binding\n If binding to an object instance, ``a.x`` is transformed into the\n call: ``type(a).__dict__[\'x\'].__get__(a, type(a))``.\n\nClass Binding\n If binding to a class, ``A.x`` is transformed into the call:\n ``A.__dict__[\'x\'].__get__(None, A)``.\n\nSuper Binding\n If ``a`` is an instance of ``super``, then the binding ``super(B,\n obj).m()`` searches ``obj.__class__.__mro__`` for the base class\n ``A`` immediately preceding ``B`` and then invokes the descriptor\n with the call: ``A.__dict__[\'m\'].__get__(obj, obj.__class__)``.\n\nFor instance bindings, the precedence of descriptor invocation depends\non the which descriptor methods are defined. A descriptor can define\nany combination of ``__get__()``, ``__set__()`` and ``__delete__()``.\nIf it does not define ``__get__()``, then accessing the attribute will\nreturn the descriptor object itself unless there is a value in the\nobject\'s instance dictionary. If the descriptor defines ``__set__()``\nand/or ``__delete__()``, it is a data descriptor; if it defines\nneither, it is a non-data descriptor. Normally, data descriptors\ndefine both ``__get__()`` and ``__set__()``, while non-data\ndescriptors have just the ``__get__()`` method. Data descriptors with\n``__set__()`` and ``__get__()`` defined always override a redefinition\nin an instance dictionary. In contrast, non-data descriptors can be\noverridden by instances.\n\nPython methods (including ``staticmethod()`` and ``classmethod()``)\nare implemented as non-data descriptors. Accordingly, instances can\nredefine and override methods. This allows individual instances to\nacquire behaviors that differ from other instances of the same class.\n\nThe ``property()`` function is implemented as a data descriptor.\nAccordingly, instances cannot override the behavior of a property.\n\n\n__slots__\n---------\n\nBy default, instances of classes have a dictionary for attribute\nstorage. This wastes space for objects having very few instance\nvariables. The space consumption can become acute when creating large\nnumbers of instances.\n\nThe default can be overridden by defining *__slots__* in a class\ndefinition. The *__slots__* declaration takes a sequence of instance\nvariables and reserves just enough space in each instance to hold a\nvalue for each variable. Space is saved because *__dict__* is not\ncreated for each instance.\n\nobject.__slots__\n\n This class variable can be assigned a string, iterable, or sequence\n of strings with variable names used by instances. If defined in a\n class, *__slots__* reserves space for the declared variables and\n prevents the automatic creation of *__dict__* and *__weakref__* for\n each instance.\n\n\nNotes on using *__slots__*\n~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n* When inheriting from a class without *__slots__*, the *__dict__*\n attribute of that class will always be accessible, so a *__slots__*\n definition in the subclass is meaningless.\n\n* Without a *__dict__* variable, instances cannot be assigned new\n variables not listed in the *__slots__* definition. Attempts to\n assign to an unlisted variable name raises ``AttributeError``. If\n dynamic assignment of new variables is desired, then add\n ``\'__dict__\'`` to the sequence of strings in the *__slots__*\n declaration.\n\n* Without a *__weakref__* variable for each instance, classes defining\n *__slots__* do not support weak references to its instances. If weak\n reference support is needed, then add ``\'__weakref__\'`` to the\n sequence of strings in the *__slots__* declaration.\n\n* *__slots__* are implemented at the class level by creating\n descriptors (*Implementing Descriptors*) for each variable name. As\n a result, class attributes cannot be used to set default values for\n instance variables defined by *__slots__*; otherwise, the class\n attribute would overwrite the descriptor assignment.\n\n* The action of a *__slots__* declaration is limited to the class\n where it is defined. As a result, subclasses will have a *__dict__*\n unless they also define *__slots__* (which must only contain names\n of any *additional* slots).\n\n* If a class defines a slot also defined in a base class, the instance\n variable defined by the base class slot is inaccessible (except by\n retrieving its descriptor directly from the base class). This\n renders the meaning of the program undefined. In the future, a\n check may be added to prevent this.\n\n* Nonempty *__slots__* does not work for classes derived from\n "variable-length" built-in types such as ``int``, ``str`` and\n ``tuple``.\n\n* Any non-string iterable may be assigned to *__slots__*. Mappings may\n also be used; however, in the future, special meaning may be\n assigned to the values corresponding to each key.\n\n* *__class__* assignment works only if both classes have the same\n *__slots__*.\n\n\nCustomizing class creation\n==========================\n\nBy default, classes are constructed using ``type()``. A class\ndefinition is read into a separate namespace and the value of class\nname is bound to the result of ``type(name, bases, dict)``.\n\nWhen the class definition is read, if a callable ``metaclass`` keyword\nargument is passed after the bases in the class definition, the\ncallable given will be called instead of ``type()``. If other keyword\narguments are passed, they will also be passed to the metaclass. This\nallows classes or functions to be written which monitor or alter the\nclass creation process:\n\n* Modifying the class dictionary prior to the class being created.\n\n* Returning an instance of another class -- essentially performing the\n role of a factory function.\n\nThese steps will have to be performed in the metaclass\'s ``__new__()``\nmethod -- ``type.__new__()`` can then be called from this method to\ncreate a class with different properties. This example adds a new\nelement to the class dictionary before creating the class:\n\n class metacls(type):\n def __new__(mcs, name, bases, dict):\n dict[\'foo\'] = \'metacls was here\'\n return type.__new__(mcs, name, bases, dict)\n\nYou can of course also override other class methods (or add new\nmethods); for example defining a custom ``__call__()`` method in the\nmetaclass allows custom behavior when the class is called, e.g. not\nalways creating a new instance.\n\nIf the metaclass has a ``__prepare__()`` attribute (usually\nimplemented as a class or static method), it is called before the\nclass body is evaluated with the name of the class and a tuple of its\nbases for arguments. It should return an object that supports the\nmapping interface that will be used to store the namespace of the\nclass. The default is a plain dictionary. This could be used, for\nexample, to keep track of the order that class attributes are declared\nin by returning an ordered dictionary.\n\nThe appropriate metaclass is determined by the following precedence\nrules:\n\n* If the ``metaclass`` keyword argument is passed with the bases, it\n is used.\n\n* Otherwise, if there is at least one base class, its metaclass is\n used.\n\n* Otherwise, the default metaclass (``type``) is used.\n\nThe potential uses for metaclasses are boundless. Some ideas that have\nbeen explored including logging, interface checking, automatic\ndelegation, automatic property creation, proxies, frameworks, and\nautomatic resource locking/synchronization.\n\nHere is an example of a metaclass that uses an\n``collections.OrderedDict`` to remember the order that class members\nwere defined:\n\n class OrderedClass(type):\n\n @classmethod\n def __prepare__(metacls, name, bases, **kwds):\n return collections.OrderedDict()\n\n def __new__(cls, name, bases, classdict):\n result = type.__new__(cls, name, bases, dict(classdict))\n result.members = tuple(classdict)\n return result\n\n class A(metaclass=OrderedClass):\n def one(self): pass\n def two(self): pass\n def three(self): pass\n def four(self): pass\n\n >>> A.members\n (\'__module__\', \'one\', \'two\', \'three\', \'four\')\n\nWhen the class definition for *A* gets executed, the process begins\nwith calling the metaclass\'s ``__prepare__()`` method which returns an\nempty ``collections.OrderedDict``. That mapping records the methods\nand attributes of *A* as they are defined within the body of the class\nstatement. Once those definitions are executed, the ordered dictionary\nis fully populated and the metaclass\'s ``__new__()`` method gets\ninvoked. That method builds the new type and it saves the ordered\ndictionary keys in an attribute called *members*.\n\n\nCustomizing instance and subclass checks\n========================================\n\nThe following methods are used to override the default behavior of the\n``isinstance()`` and ``issubclass()`` built-in functions.\n\nIn particular, the metaclass ``abc.ABCMeta`` implements these methods\nin order to allow the addition of Abstract Base Classes (ABCs) as\n"virtual base classes" to any class or type (including built-in\ntypes), including other ABCs.\n\nclass.__instancecheck__(self, instance)\n\n Return true if *instance* should be considered a (direct or\n indirect) instance of *class*. If defined, called to implement\n ``isinstance(instance, class)``.\n\nclass.__subclasscheck__(self, subclass)\n\n Return true if *subclass* should be considered a (direct or\n indirect) subclass of *class*. If defined, called to implement\n ``issubclass(subclass, class)``.\n\nNote that these methods are looked up on the type (metaclass) of a\nclass. They cannot be defined as class methods in the actual class.\nThis is consistent with the lookup of special methods that are called\non instances, only in this case the instance is itself a class.\n\nSee also:\n\n **PEP 3119** - Introducing Abstract Base Classes\n Includes the specification for customizing ``isinstance()`` and\n ``issubclass()`` behavior through ``__instancecheck__()`` and\n ``__subclasscheck__()``, with motivation for this functionality\n in the context of adding Abstract Base Classes (see the ``abc``\n module) to the language.\n\n\nEmulating callable objects\n==========================\n\nobject.__call__(self[, args...])\n\n Called when the instance is "called" as a function; if this method\n is defined, ``x(arg1, arg2, ...)`` is a shorthand for\n ``x.__call__(arg1, arg2, ...)``.\n\n\nEmulating container types\n=========================\n\nThe following methods can be defined to implement container objects.\nContainers usually are sequences (such as lists or tuples) or mappings\n(like dictionaries), but can represent other containers as well. The\nfirst set of methods is used either to emulate a sequence or to\nemulate a mapping; the difference is that for a sequence, the\nallowable keys should be the integers *k* for which ``0 <= k < N``\nwhere *N* is the length of the sequence, or slice objects, which\ndefine a range of items. It is also recommended that mappings provide\nthe methods ``keys()``, ``values()``, ``items()``, ``get()``,\n``clear()``, ``setdefault()``, ``pop()``, ``popitem()``, ``copy()``,\nand ``update()`` behaving similar to those for Python\'s standard\ndictionary objects. The ``collections`` module provides a\n``MutableMapping`` abstract base class to help create those methods\nfrom a base set of ``__getitem__()``, ``__setitem__()``,\n``__delitem__()``, and ``keys()``. Mutable sequences should provide\nmethods ``append()``, ``count()``, ``index()``, ``extend()``,\n``insert()``, ``pop()``, ``remove()``, ``reverse()`` and ``sort()``,\nlike Python standard list objects. Finally, sequence types should\nimplement addition (meaning concatenation) and multiplication (meaning\nrepetition) by defining the methods ``__add__()``, ``__radd__()``,\n``__iadd__()``, ``__mul__()``, ``__rmul__()`` and ``__imul__()``\ndescribed below; they should not define other numerical operators. It\nis recommended that both mappings and sequences implement the\n``__contains__()`` method to allow efficient use of the ``in``\noperator; for mappings, ``in`` should search the mapping\'s keys; for\nsequences, it should search through the values. It is further\nrecommended that both mappings and sequences implement the\n``__iter__()`` method to allow efficient iteration through the\ncontainer; for mappings, ``__iter__()`` should be the same as\n``keys()``; for sequences, it should iterate through the values.\n\nobject.__len__(self)\n\n Called to implement the built-in function ``len()``. Should return\n the length of the object, an integer ``>=`` 0. Also, an object\n that doesn\'t define a ``__bool__()`` method and whose ``__len__()``\n method returns zero is considered to be false in a Boolean context.\n\nNote: Slicing is done exclusively with the following three methods. A\n call like\n\n a[1:2] = b\n\n is translated to\n\n a[slice(1, 2, None)] = b\n\n and so forth. Missing slice items are always filled in with\n ``None``.\n\nobject.__getitem__(self, key)\n\n Called to implement evaluation of ``self[key]``. For sequence\n types, the accepted keys should be integers and slice objects.\n Note that the special interpretation of negative indexes (if the\n class wishes to emulate a sequence type) is up to the\n ``__getitem__()`` method. If *key* is of an inappropriate type,\n ``TypeError`` may be raised; if of a value outside the set of\n indexes for the sequence (after any special interpretation of\n negative values), ``IndexError`` should be raised. For mapping\n types, if *key* is missing (not in the container), ``KeyError``\n should be raised.\n\n Note: ``for`` loops expect that an ``IndexError`` will be raised for\n illegal indexes to allow proper detection of the end of the\n sequence.\n\nobject.__setitem__(self, key, value)\n\n Called to implement assignment to ``self[key]``. Same note as for\n ``__getitem__()``. This should only be implemented for mappings if\n the objects support changes to the values for keys, or if new keys\n can be added, or for sequences if elements can be replaced. The\n same exceptions should be raised for improper *key* values as for\n the ``__getitem__()`` method.\n\nobject.__delitem__(self, key)\n\n Called to implement deletion of ``self[key]``. Same note as for\n ``__getitem__()``. This should only be implemented for mappings if\n the objects support removal of keys, or for sequences if elements\n can be removed from the sequence. The same exceptions should be\n raised for improper *key* values as for the ``__getitem__()``\n method.\n\nobject.__iter__(self)\n\n This method is called when an iterator is required for a container.\n This method should return a new iterator object that can iterate\n over all the objects in the container. For mappings, it should\n iterate over the keys of the container, and should also be made\n available as the method ``keys()``.\n\n Iterator objects also need to implement this method; they are\n required to return themselves. For more information on iterator\n objects, see *Iterator Types*.\n\nobject.__reversed__(self)\n\n Called (if present) by the ``reversed()`` built-in to implement\n reverse iteration. It should return a new iterator object that\n iterates over all the objects in the container in reverse order.\n\n If the ``__reversed__()`` method is not provided, the\n ``reversed()`` built-in will fall back to using the sequence\n protocol (``__len__()`` and ``__getitem__()``). Objects that\n support the sequence protocol should only provide\n ``__reversed__()`` if they can provide an implementation that is\n more efficient than the one provided by ``reversed()``.\n\nThe membership test operators (``in`` and ``not in``) are normally\nimplemented as an iteration through a sequence. However, container\nobjects can supply the following special method with a more efficient\nimplementation, which also does not require the object be a sequence.\n\nobject.__contains__(self, item)\n\n Called to implement membership test operators. Should return true\n if *item* is in *self*, false otherwise. For mapping objects, this\n should consider the keys of the mapping rather than the values or\n the key-item pairs.\n\n For objects that don\'t define ``__contains__()``, the membership\n test first tries iteration via ``__iter__()``, then the old\n sequence iteration protocol via ``__getitem__()``, see *this\n section in the language reference*.\n\n\nEmulating numeric types\n=======================\n\nThe following methods can be defined to emulate numeric objects.\nMethods corresponding to operations that are not supported by the\nparticular kind of number implemented (e.g., bitwise operations for\nnon-integral numbers) should be left undefined.\n\nobject.__add__(self, other)\nobject.__sub__(self, other)\nobject.__mul__(self, other)\nobject.__truediv__(self, other)\nobject.__floordiv__(self, other)\nobject.__mod__(self, other)\nobject.__divmod__(self, other)\nobject.__pow__(self, other[, modulo])\nobject.__lshift__(self, other)\nobject.__rshift__(self, other)\nobject.__and__(self, other)\nobject.__xor__(self, other)\nobject.__or__(self, other)\n\n These methods are called to implement the binary arithmetic\n operations (``+``, ``-``, ``*``, ``/``, ``//``, ``%``,\n ``divmod()``, ``pow()``, ``**``, ``<<``, ``>>``, ``&``, ``^``,\n ``|``). For instance, to evaluate the expression ``x + y``, where\n *x* is an instance of a class that has an ``__add__()`` method,\n ``x.__add__(y)`` is called. The ``__divmod__()`` method should be\n the equivalent to using ``__floordiv__()`` and ``__mod__()``; it\n should not be related to ``__truediv__()``. Note that\n ``__pow__()`` should be defined to accept an optional third\n argument if the ternary version of the built-in ``pow()`` function\n is to be supported.\n\n If one of those methods does not support the operation with the\n supplied arguments, it should return ``NotImplemented``.\n\nobject.__radd__(self, other)\nobject.__rsub__(self, other)\nobject.__rmul__(self, other)\nobject.__rtruediv__(self, other)\nobject.__rfloordiv__(self, other)\nobject.__rmod__(self, other)\nobject.__rdivmod__(self, other)\nobject.__rpow__(self, other)\nobject.__rlshift__(self, other)\nobject.__rrshift__(self, other)\nobject.__rand__(self, other)\nobject.__rxor__(self, other)\nobject.__ror__(self, other)\n\n These methods are called to implement the binary arithmetic\n operations (``+``, ``-``, ``*``, ``/``, ``//``, ``%``,\n ``divmod()``, ``pow()``, ``**``, ``<<``, ``>>``, ``&``, ``^``,\n ``|``) with reflected (swapped) operands. These functions are only\n called if the left operand does not support the corresponding\n operation and the operands are of different types. [2] For\n instance, to evaluate the expression ``x - y``, where *y* is an\n instance of a class that has an ``__rsub__()`` method,\n ``y.__rsub__(x)`` is called if ``x.__sub__(y)`` returns\n *NotImplemented*.\n\n Note that ternary ``pow()`` will not try calling ``__rpow__()``\n (the coercion rules would become too complicated).\n\n Note: If the right operand\'s type is a subclass of the left operand\'s\n type and that subclass provides the reflected method for the\n operation, this method will be called before the left operand\'s\n non-reflected method. This behavior allows subclasses to\n override their ancestors\' operations.\n\nobject.__iadd__(self, other)\nobject.__isub__(self, other)\nobject.__imul__(self, other)\nobject.__itruediv__(self, other)\nobject.__ifloordiv__(self, other)\nobject.__imod__(self, other)\nobject.__ipow__(self, other[, modulo])\nobject.__ilshift__(self, other)\nobject.__irshift__(self, other)\nobject.__iand__(self, other)\nobject.__ixor__(self, other)\nobject.__ior__(self, other)\n\n These methods are called to implement the augmented arithmetic\n assignments (``+=``, ``-=``, ``*=``, ``/=``, ``//=``, ``%=``,\n ``**=``, ``<<=``, ``>>=``, ``&=``, ``^=``, ``|=``). These methods\n should attempt to do the operation in-place (modifying *self*) and\n return the result (which could be, but does not have to be,\n *self*). If a specific method is not defined, the augmented\n assignment falls back to the normal methods. For instance, to\n execute the statement ``x += y``, where *x* is an instance of a\n class that has an ``__iadd__()`` method, ``x.__iadd__(y)`` is\n called. If *x* is an instance of a class that does not define a\n ``__iadd__()`` method, ``x.__add__(y)`` and ``y.__radd__(x)`` are\n considered, as with the evaluation of ``x + y``.\n\nobject.__neg__(self)\nobject.__pos__(self)\nobject.__abs__(self)\nobject.__invert__(self)\n\n Called to implement the unary arithmetic operations (``-``, ``+``,\n ``abs()`` and ``~``).\n\nobject.__complex__(self)\nobject.__int__(self)\nobject.__float__(self)\nobject.__round__(self[, n])\n\n Called to implement the built-in functions ``complex()``,\n ``int()``, ``float()`` and ``round()``. Should return a value of\n the appropriate type.\n\nobject.__index__(self)\n\n Called to implement ``operator.index()``. Also called whenever\n Python needs an integer object (such as in slicing, or in the\n built-in ``bin()``, ``hex()`` and ``oct()`` functions). Must return\n an integer.\n\n\nWith Statement Context Managers\n===============================\n\nA *context manager* is an object that defines the runtime context to\nbe established when executing a ``with`` statement. The context\nmanager handles the entry into, and the exit from, the desired runtime\ncontext for the execution of the block of code. Context managers are\nnormally invoked using the ``with`` statement (described in section\n*The with statement*), but can also be used by directly invoking their\nmethods.\n\nTypical uses of context managers include saving and restoring various\nkinds of global state, locking and unlocking resources, closing opened\nfiles, etc.\n\nFor more information on context managers, see *Context Manager Types*.\n\nobject.__enter__(self)\n\n Enter the runtime context related to this object. The ``with``\n statement will bind this method\'s return value to the target(s)\n specified in the ``as`` clause of the statement, if any.\n\nobject.__exit__(self, exc_type, exc_value, traceback)\n\n Exit the runtime context related to this object. The parameters\n describe the exception that caused the context to be exited. If the\n context was exited without an exception, all three arguments will\n be ``None``.\n\n If an exception is supplied, and the method wishes to suppress the\n exception (i.e., prevent it from being propagated), it should\n return a true value. Otherwise, the exception will be processed\n normally upon exit from this method.\n\n Note that ``__exit__()`` methods should not reraise the passed-in\n exception; this is the caller\'s responsibility.\n\nSee also:\n\n **PEP 0343** - The "with" statement\n The specification, background, and examples for the Python\n ``with`` statement.\n\n\nSpecial method lookup\n=====================\n\nFor custom classes, implicit invocations of special methods are only\nguaranteed to work correctly if defined on an object\'s type, not in\nthe object\'s instance dictionary. That behaviour is the reason why\nthe following code raises an exception:\n\n >>> class C:\n ... pass\n ...\n >>> c = C()\n >>> c.__len__ = lambda: 5\n >>> len(c)\n Traceback (most recent call last):\n File "", line 1, in \n TypeError: object of type \'C\' has no len()\n\nThe rationale behind this behaviour lies with a number of special\nmethods such as ``__hash__()`` and ``__repr__()`` that are implemented\nby all objects, including type objects. If the implicit lookup of\nthese methods used the conventional lookup process, they would fail\nwhen invoked on the type object itself:\n\n >>> 1 .__hash__() == hash(1)\n True\n >>> int.__hash__() == hash(int)\n Traceback (most recent call last):\n File "", line 1, in \n TypeError: descriptor \'__hash__\' of \'int\' object needs an argument\n\nIncorrectly attempting to invoke an unbound method of a class in this\nway is sometimes referred to as \'metaclass confusion\', and is avoided\nby bypassing the instance when looking up special methods:\n\n >>> type(1).__hash__(1) == hash(1)\n True\n >>> type(int).__hash__(int) == hash(int)\n True\n\nIn addition to bypassing any instance attributes in the interest of\ncorrectness, implicit special method lookup generally also bypasses\nthe ``__getattribute__()`` method even of the object\'s metaclass:\n\n >>> class Meta(type):\n ... def __getattribute__(*args):\n ... print("Metaclass getattribute invoked")\n ... return type.__getattribute__(*args)\n ...\n >>> class C(object, metaclass=Meta):\n ... def __len__(self):\n ... return 10\n ... def __getattribute__(*args):\n ... print("Class getattribute invoked")\n ... return object.__getattribute__(*args)\n ...\n >>> c = C()\n >>> c.__len__() # Explicit lookup via instance\n Class getattribute invoked\n 10\n >>> type(c).__len__(c) # Explicit lookup via type\n Metaclass getattribute invoked\n 10\n >>> len(c) # Implicit lookup\n 10\n\nBypassing the ``__getattribute__()`` machinery in this fashion\nprovides significant scope for speed optimisations within the\ninterpreter, at the cost of some flexibility in the handling of\nspecial methods (the special method *must* be set on the class object\nitself in order to be consistently invoked by the interpreter).\n\n-[ Footnotes ]-\n\n[1] It *is* possible in some cases to change an object\'s type, under\n certain controlled conditions. It generally isn\'t a good idea\n though, since it can lead to some very strange behaviour if it is\n handled incorrectly.\n\n[2] For operands of the same type, it is assumed that if the non-\n reflected method (such as ``__add__()``) fails the operation is\n not supported, which is why the reflected method is not called.\n', + 'string-methods': '\nString Methods\n**************\n\nString objects support the methods listed below. Note that none of\nthese methods take keyword arguments.\n\nIn addition, Python\'s strings support the sequence type methods\ndescribed in the *Sequence Types --- str, bytes, bytearray, list,\ntuple, range* section. To output formatted strings, see the *String\nFormatting* section. Also, see the ``re`` module for string functions\nbased on regular expressions.\n\nstr.capitalize()\n\n Return a copy of the string with its first character capitalized\n and the rest lowercased.\n\nstr.center(width[, fillchar])\n\n Return centered in a string of length *width*. Padding is done\n using the specified *fillchar* (default is a space).\n\nstr.count(sub[, start[, end]])\n\n Return the number of non-overlapping occurrences of substring *sub*\n in the range [*start*, *end*]. Optional arguments *start* and\n *end* are interpreted as in slice notation.\n\nstr.encode([encoding[, errors]])\n\n Return an encoded version of the string as a bytes object. Default\n encoding is the current default string encoding. *errors* may be\n given to set a different error handling scheme. The default for\n *errors* is ``\'strict\'``, meaning that encoding errors raise a\n ``UnicodeError``. Other possible values are ``\'ignore\'``,\n ``\'replace\'``, ``\'xmlcharrefreplace\'``, ``\'backslashreplace\'`` and\n any other name registered via ``codecs.register_error()``, see\n section *Codec Base Classes*. For a list of possible encodings, see\n section *Standard Encodings*.\n\n Changed in version 3.1: Support for keyword arguments added.\n\nstr.endswith(suffix[, start[, end]])\n\n Return ``True`` if the string ends with the specified *suffix*,\n otherwise return ``False``. *suffix* can also be a tuple of\n suffixes to look for. With optional *start*, test beginning at\n that position. With optional *end*, stop comparing at that\n position.\n\nstr.expandtabs([tabsize])\n\n Return a copy of the string where all tab characters are replaced\n by one or more spaces, depending on the current column and the\n given tab size. The column number is reset to zero after each\n newline occurring in the string. If *tabsize* is not given, a tab\n size of ``8`` characters is assumed. This doesn\'t understand other\n non-printing characters or escape sequences.\n\nstr.find(sub[, start[, end]])\n\n Return the lowest index in the string where substring *sub* is\n found, such that *sub* is contained in the slice ``s[start:end]``.\n Optional arguments *start* and *end* are interpreted as in slice\n notation. Return ``-1`` if *sub* is not found.\n\nstr.format(*args, **kwargs)\n\n Perform a string formatting operation. The *format_string*\n argument can contain literal text or replacement fields delimited\n by braces ``{}``. Each replacement field contains either the\n numeric index of a positional argument, or the name of a keyword\n argument. Returns a copy of *format_string* where each replacement\n field is replaced with the string value of the corresponding\n argument.\n\n >>> "The sum of 1 + 2 is {0}".format(1+2)\n \'The sum of 1 + 2 is 3\'\n\n See *Format String Syntax* for a description of the various\n formatting options that can be specified in format strings.\n\nstr.index(sub[, start[, end]])\n\n Like ``find()``, but raise ``ValueError`` when the substring is not\n found.\n\nstr.isalnum()\n\n Return true if all characters in the string are alphanumeric and\n there is at least one character, false otherwise. A character\n ``c`` is alphanumeric if one of the following returns ``True``:\n ``c.isalpha()``, ``c.isdecimal()``, ``c.isdigit()``, or\n ``c.isnumeric()``.\n\nstr.isalpha()\n\n Return true if all characters in the string are alphabetic and\n there is at least one character, false otherwise. Alphabetic\n characters are those characters defined in the Unicode character\n database as "Letter", i.e., those with general category property\n being one of "Lm", "Lt", "Lu", "Ll", or "Lo". Note that this is\n different from the "Alphabetic" property defined in the Unicode\n Standard.\n\nstr.isdecimal()\n\n Return true if all characters in the string are decimal characters\n and there is at least one character, false otherwise. Decimal\n characters are those from general category "Nd". This category\n includes digit characters, and all characters that that can be used\n to form decimal-radix numbers, e.g. U+0660, ARABIC-INDIC DIGIT\n ZERO.\n\nstr.isdigit()\n\n Return true if all characters in the string are digits and there is\n at least one character, false otherwise. Digits include decimal\n characters and digits that need special handling, such as the\n compatibility superscript digits. Formally, a digit is a character\n that has the property value Numeric_Type=Digit or\n Numeric_Type=Decimal.\n\nstr.isidentifier()\n\n Return true if the string is a valid identifier according to the\n language definition, section *Identifiers and keywords*.\n\nstr.islower()\n\n Return true if all cased characters in the string are lowercase and\n there is at least one cased character, false otherwise. Cased\n characters are those with general category property being one of\n "Lu", "Ll", or "Lt" and lowercase characters are those with general\n category property "Ll".\n\nstr.isnumeric()\n\n Return true if all characters in the string are numeric characters,\n and there is at least one character, false otherwise. Numeric\n characters include digit characters, and all characters that have\n the Unicode numeric value property, e.g. U+2155, VULGAR FRACTION\n ONE FIFTH. Formally, numeric characters are those with the\n property value Numeric_Type=Digit, Numeric_Type=Decimal or\n Numeric_Type=Numeric.\n\nstr.isprintable()\n\n Return true if all characters in the string are printable or the\n string is empty, false otherwise. Nonprintable characters are\n those characters defined in the Unicode character database as\n "Other" or "Separator", excepting the ASCII space (0x20) which is\n considered printable. (Note that printable characters in this\n context are those which should not be escaped when ``repr()`` is\n invoked on a string. It has no bearing on the handling of strings\n written to ``sys.stdout`` or ``sys.stderr``.)\n\nstr.isspace()\n\n Return true if there are only whitespace characters in the string\n and there is at least one character, false otherwise. Whitespace\n characters are those characters defined in the Unicode character\n database as "Other" or "Separator" and those with bidirectional\n property being one of "WS", "B", or "S".\n\nstr.istitle()\n\n Return true if the string is a titlecased string and there is at\n least one character, for example uppercase characters may only\n follow uncased characters and lowercase characters only cased ones.\n Return false otherwise.\n\nstr.isupper()\n\n Return true if all cased characters in the string are uppercase and\n there is at least one cased character, false otherwise. Cased\n characters are those with general category property being one of\n "Lu", "Ll", or "Lt" and uppercase characters are those with general\n category property "Lu".\n\nstr.join(iterable)\n\n Return a string which is the concatenation of the strings in the\n *iterable* *iterable*. A ``TypeError`` will be raised if there are\n any non-string values in *seq*, including ``bytes`` objects. The\n separator between elements is the string providing this method.\n\nstr.ljust(width[, fillchar])\n\n Return the string left justified in a string of length *width*.\n Padding is done using the specified *fillchar* (default is a\n space). The original string is returned if *width* is less than\n ``len(s)``.\n\nstr.lower()\n\n Return a copy of the string converted to lowercase.\n\nstr.lstrip([chars])\n\n Return a copy of the string with leading characters removed. The\n *chars* argument is a string specifying the set of characters to be\n removed. If omitted or ``None``, the *chars* argument defaults to\n removing whitespace. The *chars* argument is not a prefix; rather,\n all combinations of its values are stripped:\n\n >>> \' spacious \'.lstrip()\n \'spacious \'\n >>> \'www.example.com\'.lstrip(\'cmowz.\')\n \'example.com\'\n\nstatic str.maketrans(x[, y[, z]])\n\n This static method returns a translation table usable for\n ``str.translate()``.\n\n If there is only one argument, it must be a dictionary mapping\n Unicode ordinals (integers) or characters (strings of length 1) to\n Unicode ordinals, strings (of arbitrary lengths) or None.\n Character keys will then be converted to ordinals.\n\n If there are two arguments, they must be strings of equal length,\n and in the resulting dictionary, each character in x will be mapped\n to the character at the same position in y. If there is a third\n argument, it must be a string, whose characters will be mapped to\n None in the result.\n\nstr.partition(sep)\n\n Split the string at the first occurrence of *sep*, and return a\n 3-tuple containing the part before the separator, the separator\n itself, and the part after the separator. If the separator is not\n found, return a 3-tuple containing the string itself, followed by\n two empty strings.\n\nstr.replace(old, new[, count])\n\n Return a copy of the string with all occurrences of substring *old*\n replaced by *new*. If the optional argument *count* is given, only\n the first *count* occurrences are replaced.\n\nstr.rfind(sub[, start[, end]])\n\n Return the highest index in the string where substring *sub* is\n found, such that *sub* is contained within ``s[start:end]``.\n Optional arguments *start* and *end* are interpreted as in slice\n notation. Return ``-1`` on failure.\n\nstr.rindex(sub[, start[, end]])\n\n Like ``rfind()`` but raises ``ValueError`` when the substring *sub*\n is not found.\n\nstr.rjust(width[, fillchar])\n\n Return the string right justified in a string of length *width*.\n Padding is done using the specified *fillchar* (default is a\n space). The original string is returned if *width* is less than\n ``len(s)``.\n\nstr.rpartition(sep)\n\n Split the string at the last occurrence of *sep*, and return a\n 3-tuple containing the part before the separator, the separator\n itself, and the part after the separator. If the separator is not\n found, return a 3-tuple containing two empty strings, followed by\n the string itself.\n\nstr.rsplit([sep[, maxsplit]])\n\n Return a list of the words in the string, using *sep* as the\n delimiter string. If *maxsplit* is given, at most *maxsplit* splits\n are done, the *rightmost* ones. If *sep* is not specified or\n ``None``, any whitespace string is a separator. Except for\n splitting from the right, ``rsplit()`` behaves like ``split()``\n which is described in detail below.\n\nstr.rstrip([chars])\n\n Return a copy of the string with trailing characters removed. The\n *chars* argument is a string specifying the set of characters to be\n removed. If omitted or ``None``, the *chars* argument defaults to\n removing whitespace. The *chars* argument is not a suffix; rather,\n all combinations of its values are stripped:\n\n >>> \' spacious \'.rstrip()\n \' spacious\'\n >>> \'mississippi\'.rstrip(\'ipz\')\n \'mississ\'\n\nstr.split([sep[, maxsplit]])\n\n Return a list of the words in the string, using *sep* as the\n delimiter string. If *maxsplit* is given, at most *maxsplit*\n splits are done (thus, the list will have at most ``maxsplit+1``\n elements). If *maxsplit* is not specified, then there is no limit\n on the number of splits (all possible splits are made).\n\n If *sep* is given, consecutive delimiters are not grouped together\n and are deemed to delimit empty strings (for example,\n ``\'1,,2\'.split(\',\')`` returns ``[\'1\', \'\', \'2\']``). The *sep*\n argument may consist of multiple characters (for example,\n ``\'1<>2<>3\'.split(\'<>\')`` returns ``[\'1\', \'2\', \'3\']``). Splitting\n an empty string with a specified separator returns ``[\'\']``.\n\n If *sep* is not specified or is ``None``, a different splitting\n algorithm is applied: runs of consecutive whitespace are regarded\n as a single separator, and the result will contain no empty strings\n at the start or end if the string has leading or trailing\n whitespace. Consequently, splitting an empty string or a string\n consisting of just whitespace with a ``None`` separator returns\n ``[]``.\n\n For example, ``\' 1 2 3 \'.split()`` returns ``[\'1\', \'2\', \'3\']``,\n and ``\' 1 2 3 \'.split(None, 1)`` returns ``[\'1\', \'2 3 \']``.\n\nstr.splitlines([keepends])\n\n Return a list of the lines in the string, breaking at line\n boundaries. Line breaks are not included in the resulting list\n unless *keepends* is given and true.\n\nstr.startswith(prefix[, start[, end]])\n\n Return ``True`` if string starts with the *prefix*, otherwise\n return ``False``. *prefix* can also be a tuple of prefixes to look\n for. With optional *start*, test string beginning at that\n position. With optional *end*, stop comparing string at that\n position.\n\nstr.strip([chars])\n\n Return a copy of the string with the leading and trailing\n characters removed. The *chars* argument is a string specifying the\n set of characters to be removed. If omitted or ``None``, the\n *chars* argument defaults to removing whitespace. The *chars*\n argument is not a prefix or suffix; rather, all combinations of its\n values are stripped:\n\n >>> \' spacious \'.strip()\n \'spacious\'\n >>> \'www.example.com\'.strip(\'cmowz.\')\n \'example\'\n\nstr.swapcase()\n\n Return a copy of the string with uppercase characters converted to\n lowercase and vice versa.\n\nstr.title()\n\n Return a titlecased version of the string where words start with an\n uppercase character and the remaining characters are lowercase.\n\n The algorithm uses a simple language-independent definition of a\n word as groups of consecutive letters. The definition works in\n many contexts but it means that apostrophes in contractions and\n possessives form word boundaries, which may not be the desired\n result:\n\n >>> "they\'re bill\'s friends from the UK".title()\n "They\'Re Bill\'S Friends From The Uk"\n\n A workaround for apostrophes can be constructed using regular\n expressions:\n\n >>> import re\n >>> def titlecase(s):\n return re.sub(r"[A-Za-z]+(\'[A-Za-z]+)?",\n lambda mo: mo.group(0)[0].upper() +\n mo.group(0)[1:].lower(),\n s)\n\n >>> titlecase("they\'re bill\'s friends.")\n "They\'re Bill\'s Friends."\n\nstr.translate(map)\n\n Return a copy of the *s* where all characters have been mapped\n through the *map* which must be a dictionary of Unicode ordinals\n (integers) to Unicode ordinals, strings or ``None``. Unmapped\n characters are left untouched. Characters mapped to ``None`` are\n deleted.\n\n You can use ``str.maketrans()`` to create a translation map from\n character-to-character mappings in different formats.\n\n Note: An even more flexible approach is to create a custom character\n mapping codec using the ``codecs`` module (see\n ``encodings.cp1251`` for an example).\n\nstr.upper()\n\n Return a copy of the string converted to uppercase.\n\nstr.zfill(width)\n\n Return the numeric string left filled with zeros in a string of\n length *width*. A sign prefix is handled correctly. The original\n string is returned if *width* is less than ``len(s)``.\n', + 'strings': '\nString and Bytes literals\n*************************\n\nString literals are described by the following lexical definitions:\n\n stringliteral ::= [stringprefix](shortstring | longstring)\n stringprefix ::= "r" | "R"\n shortstring ::= "\'" shortstringitem* "\'" | \'"\' shortstringitem* \'"\'\n longstring ::= "\'\'\'" longstringitem* "\'\'\'" | \'"""\' longstringitem* \'"""\'\n shortstringitem ::= shortstringchar | stringescapeseq\n longstringitem ::= longstringchar | stringescapeseq\n shortstringchar ::= \n longstringchar ::= \n stringescapeseq ::= "\\" \n\n bytesliteral ::= bytesprefix(shortbytes | longbytes)\n bytesprefix ::= "b" | "B" | "br" | "Br" | "bR" | "BR"\n shortbytes ::= "\'" shortbytesitem* "\'" | \'"\' shortbytesitem* \'"\'\n longbytes ::= "\'\'\'" longbytesitem* "\'\'\'" | \'"""\' longbytesitem* \'"""\'\n shortbytesitem ::= shortbyteschar | bytesescapeseq\n longbytesitem ::= longbyteschar | bytesescapeseq\n shortbyteschar ::= \n longbyteschar ::= \n bytesescapeseq ::= "\\" \n\nOne syntactic restriction not indicated by these productions is that\nwhitespace is not allowed between the **stringprefix** or\n**bytesprefix** and the rest of the literal. The source character set\nis defined by the encoding declaration; it is UTF-8 if no encoding\ndeclaration is given in the source file; see section *Encoding\ndeclarations*.\n\nIn plain English: Both types of literals can be enclosed in matching\nsingle quotes (``\'``) or double quotes (``"``). They can also be\nenclosed in matching groups of three single or double quotes (these\nare generally referred to as *triple-quoted strings*). The backslash\n(``\\``) character is used to escape characters that otherwise have a\nspecial meaning, such as newline, backslash itself, or the quote\ncharacter.\n\nBytes literals are always prefixed with ``\'b\'`` or ``\'B\'``; they\nproduce an instance of the ``bytes`` type instead of the ``str`` type.\nThey may only contain ASCII characters; bytes with a numeric value of\n128 or greater must be expressed with escapes.\n\nBoth string and bytes literals may optionally be prefixed with a\nletter ``\'r\'`` or ``\'R\'``; such strings are called *raw strings* and\ntreat backslashes as literal characters. As a result, in string\nliterals, ``\'\\U\'`` and ``\'\\u\'`` escapes in raw strings are not treated\nspecially.\n\nIn triple-quoted strings, unescaped newlines and quotes are allowed\n(and are retained), except that three unescaped quotes in a row\nterminate the string. (A "quote" is the character used to open the\nstring, i.e. either ``\'`` or ``"``.)\n\nUnless an ``\'r\'`` or ``\'R\'`` prefix is present, escape sequences in\nstrings are interpreted according to rules similar to those used by\nStandard C. The recognized escape sequences are:\n\n+-------------------+-----------------------------------+---------+\n| Escape Sequence | Meaning | Notes |\n+===================+===================================+=========+\n| ``\\newline`` | Backslash and newline ignored | |\n+-------------------+-----------------------------------+---------+\n| ``\\\\`` | Backslash (``\\``) | |\n+-------------------+-----------------------------------+---------+\n| ``\\\'`` | Single quote (``\'``) | |\n+-------------------+-----------------------------------+---------+\n| ``\\"`` | Double quote (``"``) | |\n+-------------------+-----------------------------------+---------+\n| ``\\a`` | ASCII Bell (BEL) | |\n+-------------------+-----------------------------------+---------+\n| ``\\b`` | ASCII Backspace (BS) | |\n+-------------------+-----------------------------------+---------+\n| ``\\f`` | ASCII Formfeed (FF) | |\n+-------------------+-----------------------------------+---------+\n| ``\\n`` | ASCII Linefeed (LF) | |\n+-------------------+-----------------------------------+---------+\n| ``\\r`` | ASCII Carriage Return (CR) | |\n+-------------------+-----------------------------------+---------+\n| ``\\t`` | ASCII Horizontal Tab (TAB) | |\n+-------------------+-----------------------------------+---------+\n| ``\\v`` | ASCII Vertical Tab (VT) | |\n+-------------------+-----------------------------------+---------+\n| ``\\ooo`` | Character with octal value *ooo* | (1,3) |\n+-------------------+-----------------------------------+---------+\n| ``\\xhh`` | Character with hex value *hh* | (2,3) |\n+-------------------+-----------------------------------+---------+\n\nEscape sequences only recognized in string literals are:\n\n+-------------------+-----------------------------------+---------+\n| Escape Sequence | Meaning | Notes |\n+===================+===================================+=========+\n| ``\\N{name}`` | Character named *name* in the | |\n| | Unicode database | |\n+-------------------+-----------------------------------+---------+\n| ``\\uxxxx`` | Character with 16-bit hex value | (4) |\n| | *xxxx* | |\n+-------------------+-----------------------------------+---------+\n| ``\\Uxxxxxxxx`` | Character with 32-bit hex value | (5) |\n| | *xxxxxxxx* | |\n+-------------------+-----------------------------------+---------+\n\nNotes:\n\n1. As in Standard C, up to three octal digits are accepted.\n\n2. Unlike in Standard C, exactly two hex digits are required.\n\n3. In a bytes literal, hexadecimal and octal escapes denote the byte\n with the given value. In a string literal, these escapes denote a\n Unicode character with the given value.\n\n4. Individual code units which form parts of a surrogate pair can be\n encoded using this escape sequence. Exactly four hex digits are\n required.\n\n5. Any Unicode character can be encoded this way, but characters\n outside the Basic Multilingual Plane (BMP) will be encoded using a\n surrogate pair if Python is compiled to use 16-bit code units (the\n default). Exactly eight hex digits are required.\n\nUnlike Standard C, all unrecognized escape sequences are left in the\nstring unchanged, i.e., *the backslash is left in the string*. (This\nbehavior is useful when debugging: if an escape sequence is mistyped,\nthe resulting output is more easily recognized as broken.) It is also\nimportant to note that the escape sequences only recognized in string\nliterals fall into the category of unrecognized escapes for bytes\nliterals.\n\nEven in a raw string, string quotes can be escaped with a backslash,\nbut the backslash remains in the string; for example, ``r"\\""`` is a\nvalid string literal consisting of two characters: a backslash and a\ndouble quote; ``r"\\"`` is not a valid string literal (even a raw\nstring cannot end in an odd number of backslashes). Specifically, *a\nraw string cannot end in a single backslash* (since the backslash\nwould escape the following quote character). Note also that a single\nbackslash followed by a newline is interpreted as those two characters\nas part of the string, *not* as a line continuation.\n', + 'subscriptions': '\nSubscriptions\n*************\n\nA subscription selects an item of a sequence (string, tuple or list)\nor mapping (dictionary) object:\n\n subscription ::= primary "[" expression_list "]"\n\nThe primary must evaluate to an object that supports subscription,\ne.g. a list or dictionary. User-defined objects can support\nsubscription by defining a ``__getitem__()`` method.\n\nFor built-in objects, there are two types of objects that support\nsubscription:\n\nIf the primary is a mapping, the expression list must evaluate to an\nobject whose value is one of the keys of the mapping, and the\nsubscription selects the value in the mapping that corresponds to that\nkey. (The expression list is a tuple except if it has exactly one\nitem.)\n\nIf the primary is a sequence, the expression (list) must evaluate to\nan integer or a slice (as discussed in the following section).\n\nThe formal syntax makes no special provision for negative indices in\nsequences; however, built-in sequences all provide a ``__getitem__()``\nmethod that interprets negative indices by adding the length of the\nsequence to the index (so that ``x[-1]`` selects the last item of\n``x``). The resulting value must be a nonnegative integer less than\nthe number of items in the sequence, and the subscription selects the\nitem whose index is that value (counting from zero). Since the support\nfor negative indices and slicing occurs in the object\'s\n``__getitem__()`` method, subclasses overriding this method will need\nto explicitly add that support.\n\nA string\'s items are characters. A character is not a separate data\ntype but a string of exactly one character.\n', 'truth': "\nTruth Value Testing\n*******************\n\nAny object can be tested for truth value, for use in an ``if`` or\n``while`` condition or as operand of the Boolean operations below. The\nfollowing values are considered false:\n\n* ``None``\n\n* ``False``\n\n* zero of any numeric type, for example, ``0``, ``0.0``, ``0j``.\n\n* any empty sequence, for example, ``''``, ``()``, ``[]``.\n\n* any empty mapping, for example, ``{}``.\n\n* instances of user-defined classes, if the class defines a\n ``__bool__()`` or ``__len__()`` method, when that method returns the\n integer zero or ``bool`` value ``False``. [1]\n\nAll other values are considered true --- so objects of many types are\nalways true.\n\nOperations and built-in functions that have a Boolean result always\nreturn ``0`` or ``False`` for false and ``1`` or ``True`` for true,\nunless otherwise stated. (Important exception: the Boolean operations\n``or`` and ``and`` always return one of their operands.)\n", - 'try': '\nThe ``try`` statement\n*********************\n\nThe ``try`` statement specifies exception handlers and/or cleanup code\nfor a group of statements:\n\n try_stmt ::= try1_stmt | try2_stmt\n try1_stmt ::= "try" ":" suite\n ("except" [expression ["as" target]] ":" suite)+\n ["else" ":" suite]\n ["finally" ":" suite]\n try2_stmt ::= "try" ":" suite\n "finally" ":" suite\n\nThe ``except`` clause(s) specify one or more exception handlers. When\nno exception occurs in the ``try`` clause, no exception handler is\nexecuted. When an exception occurs in the ``try`` suite, a search for\nan exception handler is started. This search inspects the except\nclauses in turn until one is found that matches the exception. An\nexpression-less except clause, if present, must be last; it matches\nany exception. For an except clause with an expression, that\nexpression is evaluated, and the clause matches the exception if the\nresulting object is "compatible" with the exception. An object is\ncompatible with an exception if it is the class or a base class of the\nexception object or a tuple containing an item compatible with the\nexception.\n\nIf no except clause matches the exception, the search for an exception\nhandler continues in the surrounding code and on the invocation stack.\n[1]\n\nIf the evaluation of an expression in the header of an except clause\nraises an exception, the original search for a handler is canceled and\na search starts for the new exception in the surrounding code and on\nthe call stack (it is treated as if the entire ``try`` statement\nraised the exception).\n\nWhen a matching except clause is found, the exception is assigned to\nthe target specified after the ``as`` keyword in that except clause,\nif present, and the except clause\'s suite is executed. All except\nclauses must have an executable block. When the end of this block is\nreached, execution continues normally after the entire try statement.\n(This means that if two nested handlers exist for the same exception,\nand the exception occurs in the try clause of the inner handler, the\nouter handler will not handle the exception.)\n\nWhen an exception has been assigned using ``as target``, it is cleared\nat the end of the except clause. This is as if\n\n except E as N:\n foo\n\nwas translated to\n\n except E as N:\n try:\n foo\n finally:\n N = None\n del N\n\nThat means that you have to assign the exception to a different name\nif you want to be able to refer to it after the except clause. The\nreason for this is that with the traceback attached to them,\nexceptions will form a reference cycle with the stack frame, keeping\nall locals in that frame alive until the next garbage collection\noccurs.\n\nBefore an except clause\'s suite is executed, details about the\nexception are stored in the ``sys`` module and can be access via\n``sys.exc_info()``. ``sys.exc_info()`` returns a 3-tuple consisting\nof: ``exc_type``, the exception class; ``exc_value``, the exception\ninstance; ``exc_traceback``, a traceback object (see section *The\nstandard type hierarchy*) identifying the point in the program where\nthe exception occurred. ``sys.exc_info()`` values are restored to\ntheir previous values (before the call) when returning from a function\nthat handled an exception.\n\nThe optional ``else`` clause is executed if and when control flows off\nthe end of the ``try`` clause. [2] Exceptions in the ``else`` clause\nare not handled by the preceding ``except`` clauses.\n\nIf ``finally`` is present, it specifies a \'cleanup\' handler. The\n``try`` clause is executed, including any ``except`` and ``else``\nclauses. If an exception occurs in any of the clauses and is not\nhandled, the exception is temporarily saved. The ``finally`` clause is\nexecuted. If there is a saved exception, it is re-raised at the end\nof the ``finally`` clause. If the ``finally`` clause raises another\nexception or executes a ``return`` or ``break`` statement, the saved\nexception is lost. The exception information is not available to the\nprogram during execution of the ``finally`` clause.\n\nWhen a ``return``, ``break`` or ``continue`` statement is executed in\nthe ``try`` suite of a ``try``...``finally`` statement, the\n``finally`` clause is also executed \'on the way out.\' A ``continue``\nstatement is illegal in the ``finally`` clause. (The reason is a\nproblem with the current implementation --- this restriction may be\nlifted in the future).\n\nAdditional information on exceptions can be found in section\n*Exceptions*, and information on using the ``raise`` statement to\ngenerate exceptions may be found in section *The raise statement*.\n', - 'types': '\nThe standard type hierarchy\n***************************\n\nBelow is a list of the types that are built into Python. Extension\nmodules (written in C, Java, or other languages, depending on the\nimplementation) can define additional types. Future versions of\nPython may add types to the type hierarchy (e.g., rational numbers,\nefficiently stored arrays of integers, etc.), although such additions\nwill often be provided via the standard library instead.\n\nSome of the type descriptions below contain a paragraph listing\n\'special attributes.\' These are attributes that provide access to the\nimplementation and are not intended for general use. Their definition\nmay change in the future.\n\nNone\n This type has a single value. There is a single object with this\n value. This object is accessed through the built-in name ``None``.\n It is used to signify the absence of a value in many situations,\n e.g., it is returned from functions that don\'t explicitly return\n anything. Its truth value is false.\n\nNotImplemented\n This type has a single value. There is a single object with this\n value. This object is accessed through the built-in name\n ``NotImplemented``. Numeric methods and rich comparison methods may\n return this value if they do not implement the operation for the\n operands provided. (The interpreter will then try the reflected\n operation, or some other fallback, depending on the operator.) Its\n truth value is true.\n\nEllipsis\n This type has a single value. There is a single object with this\n value. This object is accessed through the literal ``...`` or the\n built-in name ``Ellipsis``. Its truth value is true.\n\n``numbers.Number``\n These are created by numeric literals and returned as results by\n arithmetic operators and arithmetic built-in functions. Numeric\n objects are immutable; once created their value never changes.\n Python numbers are of course strongly related to mathematical\n numbers, but subject to the limitations of numerical representation\n in computers.\n\n Python distinguishes between integers, floating point numbers, and\n complex numbers:\n\n ``numbers.Integral``\n These represent elements from the mathematical set of integers\n (positive and negative).\n\n There are two types of integers:\n\n Integers (``int``)\n\n These represent numbers in an unlimited range, subject to\n available (virtual) memory only. For the purpose of shift\n and mask operations, a binary representation is assumed, and\n negative numbers are represented in a variant of 2\'s\n complement which gives the illusion of an infinite string of\n sign bits extending to the left.\n\n Booleans (``bool``)\n These represent the truth values False and True. The two\n objects representing the values False and True are the only\n Boolean objects. The Boolean type is a subtype of the integer\n type, and Boolean values behave like the values 0 and 1,\n respectively, in almost all contexts, the exception being\n that when converted to a string, the strings ``"False"`` or\n ``"True"`` are returned, respectively.\n\n The rules for integer representation are intended to give the\n most meaningful interpretation of shift and mask operations\n involving negative integers.\n\n ``numbers.Real`` (``float``)\n These represent machine-level double precision floating point\n numbers. You are at the mercy of the underlying machine\n architecture (and C or Java implementation) for the accepted\n range and handling of overflow. Python does not support single-\n precision floating point numbers; the savings in processor and\n memory usage that are usually the reason for using these is\n dwarfed by the overhead of using objects in Python, so there is\n no reason to complicate the language with two kinds of floating\n point numbers.\n\n ``numbers.Complex`` (``complex``)\n These represent complex numbers as a pair of machine-level\n double precision floating point numbers. The same caveats apply\n as for floating point numbers. The real and imaginary parts of a\n complex number ``z`` can be retrieved through the read-only\n attributes ``z.real`` and ``z.imag``.\n\nSequences\n These represent finite ordered sets indexed by non-negative\n numbers. The built-in function ``len()`` returns the number of\n items of a sequence. When the length of a sequence is *n*, the\n index set contains the numbers 0, 1, ..., *n*-1. Item *i* of\n sequence *a* is selected by ``a[i]``.\n\n Sequences also support slicing: ``a[i:j]`` selects all items with\n index *k* such that *i* ``<=`` *k* ``<`` *j*. When used as an\n expression, a slice is a sequence of the same type. This implies\n that the index set is renumbered so that it starts at 0.\n\n Some sequences also support "extended slicing" with a third "step"\n parameter: ``a[i:j:k]`` selects all items of *a* with index *x*\n where ``x = i + n*k``, *n* ``>=`` ``0`` and *i* ``<=`` *x* ``<``\n *j*.\n\n Sequences are distinguished according to their mutability:\n\n Immutable sequences\n An object of an immutable sequence type cannot change once it is\n created. (If the object contains references to other objects,\n these other objects may be mutable and may be changed; however,\n the collection of objects directly referenced by an immutable\n object cannot change.)\n\n The following types are immutable sequences:\n\n Strings\n The items of a string object are Unicode code units. A\n Unicode code unit is represented by a string object of one\n item and can hold either a 16-bit or 32-bit value\n representing a Unicode ordinal (the maximum value for the\n ordinal is given in ``sys.maxunicode``, and depends on how\n Python is configured at compile time). Surrogate pairs may\n be present in the Unicode object, and will be reported as two\n separate items. The built-in functions ``chr()`` and\n ``ord()`` convert between code units and nonnegative integers\n representing the Unicode ordinals as defined in the Unicode\n Standard 3.0. Conversion from and to other encodings are\n possible through the string method ``encode()``.\n\n Tuples\n The items of a tuple are arbitrary Python objects. Tuples of\n two or more items are formed by comma-separated lists of\n expressions. A tuple of one item (a \'singleton\') can be\n formed by affixing a comma to an expression (an expression by\n itself does not create a tuple, since parentheses must be\n usable for grouping of expressions). An empty tuple can be\n formed by an empty pair of parentheses.\n\n Bytes\n A bytes object is an immutable array. The items are 8-bit\n bytes, represented by integers in the range 0 <= x < 256.\n Bytes literals (like ``b\'abc\'`` and the built-in function\n ``bytes()`` can be used to construct bytes objects. Also,\n bytes objects can be decoded to strings via the ``decode()``\n method.\n\n Mutable sequences\n Mutable sequences can be changed after they are created. The\n subscription and slicing notations can be used as the target of\n assignment and ``del`` (delete) statements.\n\n There are currently two intrinsic mutable sequence types:\n\n Lists\n The items of a list are arbitrary Python objects. Lists are\n formed by placing a comma-separated list of expressions in\n square brackets. (Note that there are no special cases needed\n to form lists of length 0 or 1.)\n\n Byte Arrays\n A bytearray object is a mutable array. They are created by\n the built-in ``bytearray()`` constructor. Aside from being\n mutable (and hence unhashable), byte arrays otherwise provide\n the same interface and functionality as immutable bytes\n objects.\n\n The extension module ``array`` provides an additional example of\n a mutable sequence type, as does the ``collections`` module.\n\nSet types\n These represent unordered, finite sets of unique, immutable\n objects. As such, they cannot be indexed by any subscript. However,\n they can be iterated over, and the built-in function ``len()``\n returns the number of items in a set. Common uses for sets are fast\n membership testing, removing duplicates from a sequence, and\n computing mathematical operations such as intersection, union,\n difference, and symmetric difference.\n\n For set elements, the same immutability rules apply as for\n dictionary keys. Note that numeric types obey the normal rules for\n numeric comparison: if two numbers compare equal (e.g., ``1`` and\n ``1.0``), only one of them can be contained in a set.\n\n There are currently two intrinsic set types:\n\n Sets\n These represent a mutable set. They are created by the built-in\n ``set()`` constructor and can be modified afterwards by several\n methods, such as ``add()``.\n\n Frozen sets\n These represent an immutable set. They are created by the\n built-in ``frozenset()`` constructor. As a frozenset is\n immutable and *hashable*, it can be used again as an element of\n another set, or as a dictionary key.\n\nMappings\n These represent finite sets of objects indexed by arbitrary index\n sets. The subscript notation ``a[k]`` selects the item indexed by\n ``k`` from the mapping ``a``; this can be used in expressions and\n as the target of assignments or ``del`` statements. The built-in\n function ``len()`` returns the number of items in a mapping.\n\n There is currently a single intrinsic mapping type:\n\n Dictionaries\n These represent finite sets of objects indexed by nearly\n arbitrary values. The only types of values not acceptable as\n keys are values containing lists or dictionaries or other\n mutable types that are compared by value rather than by object\n identity, the reason being that the efficient implementation of\n dictionaries requires a key\'s hash value to remain constant.\n Numeric types used for keys obey the normal rules for numeric\n comparison: if two numbers compare equal (e.g., ``1`` and\n ``1.0``) then they can be used interchangeably to index the same\n dictionary entry.\n\n Dictionaries are mutable; they can be created by the ``{...}``\n notation (see section *Dictionary displays*).\n\n The extension modules ``dbm.ndbm`` and ``dbm.gnu`` provide\n additional examples of mapping types, as does the\n ``collections`` module.\n\nCallable types\n These are the types to which the function call operation (see\n section *Calls*) can be applied:\n\n User-defined functions\n A user-defined function object is created by a function\n definition (see section *Function definitions*). It should be\n called with an argument list containing the same number of items\n as the function\'s formal parameter list.\n\n Special attributes:\n\n +---------------------------+---------------------------------+-------------+\n | Attribute | Meaning | |\n +===========================+=================================+=============+\n | ``__doc__`` | The function\'s documentation | Writable |\n | | string, or ``None`` if | |\n | | unavailable | |\n +---------------------------+---------------------------------+-------------+\n | ``__name__`` | The function\'s name | Writable |\n +---------------------------+---------------------------------+-------------+\n | ``__module__`` | The name of the module the | Writable |\n | | function was defined in, or | |\n | | ``None`` if unavailable. | |\n +---------------------------+---------------------------------+-------------+\n | ``__defaults__`` | A tuple containing default | Writable |\n | | argument values for those | |\n | | arguments that have defaults, | |\n | | or ``None`` if no arguments | |\n | | have a default value | |\n +---------------------------+---------------------------------+-------------+\n | ``__code__`` | The code object representing | Writable |\n | | the compiled function body. | |\n +---------------------------+---------------------------------+-------------+\n | ``__globals__`` | A reference to the dictionary | Read-only |\n | | that holds the function\'s | |\n | | global variables --- the global | |\n | | namespace of the module in | |\n | | which the function was defined. | |\n +---------------------------+---------------------------------+-------------+\n | ``__dict__`` | The namespace supporting | Writable |\n | | arbitrary function attributes. | |\n +---------------------------+---------------------------------+-------------+\n | ``__closure__`` | ``None`` or a tuple of cells | Read-only |\n | | that contain bindings for the | |\n | | function\'s free variables. | |\n +---------------------------+---------------------------------+-------------+\n | ``__annotations__`` | A dict containing annotations | Writable |\n | | of parameters. The keys of the | |\n | | dict are the parameter names, | |\n | | or ``\'return\'`` for the return | |\n | | annotation, if provided. | |\n +---------------------------+---------------------------------+-------------+\n | ``__kwdefaults__`` | A dict containing defaults for | Writable |\n | | keyword-only parameters. | |\n +---------------------------+---------------------------------+-------------+\n\n Most of the attributes labelled "Writable" check the type of the\n assigned value.\n\n Function objects also support getting and setting arbitrary\n attributes, which can be used, for example, to attach metadata\n to functions. Regular attribute dot-notation is used to get and\n set such attributes. *Note that the current implementation only\n supports function attributes on user-defined functions. Function\n attributes on built-in functions may be supported in the\n future.*\n\n Additional information about a function\'s definition can be\n retrieved from its code object; see the description of internal\n types below.\n\n Instance methods\n An instance method object combines a class, a class instance and\n any callable object (normally a user-defined function).\n\n Special read-only attributes: ``__self__`` is the class instance\n object, ``__func__`` is the function object; ``__doc__`` is the\n method\'s documentation (same as ``__func__.__doc__``);\n ``__name__`` is the method name (same as ``__func__.__name__``);\n ``__module__`` is the name of the module the method was defined\n in, or ``None`` if unavailable.\n\n Methods also support accessing (but not setting) the arbitrary\n function attributes on the underlying function object.\n\n User-defined method objects may be created when getting an\n attribute of a class (perhaps via an instance of that class), if\n that attribute is a user-defined function object or a class\n method object.\n\n When an instance method object is created by retrieving a user-\n defined function object from a class via one of its instances,\n its ``__self__`` attribute is the instance, and the method\n object is said to be bound. The new method\'s ``__func__``\n attribute is the original function object.\n\n When a user-defined method object is created by retrieving\n another method object from a class or instance, the behaviour is\n the same as for a function object, except that the ``__func__``\n attribute of the new instance is not the original method object\n but its ``__func__`` attribute.\n\n When an instance method object is created by retrieving a class\n method object from a class or instance, its ``__self__``\n attribute is the class itself, and its ``__func__`` attribute is\n the function object underlying the class method.\n\n When an instance method object is called, the underlying\n function (``__func__``) is called, inserting the class instance\n (``__self__``) in front of the argument list. For instance,\n when ``C`` is a class which contains a definition for a function\n ``f()``, and ``x`` is an instance of ``C``, calling ``x.f(1)``\n is equivalent to calling ``C.f(x, 1)``.\n\n When an instance method object is derived from a class method\n object, the "class instance" stored in ``__self__`` will\n actually be the class itself, so that calling either ``x.f(1)``\n or ``C.f(1)`` is equivalent to calling ``f(C,1)`` where ``f`` is\n the underlying function.\n\n Note that the transformation from function object to instance\n method object happens each time the attribute is retrieved from\n the instance. In some cases, a fruitful optimization is to\n assign the attribute to a local variable and call that local\n variable. Also notice that this transformation only happens for\n user-defined functions; other callable objects (and all non-\n callable objects) are retrieved without transformation. It is\n also important to note that user-defined functions which are\n attributes of a class instance are not converted to bound\n methods; this *only* happens when the function is an attribute\n of the class.\n\n Generator functions\n A function or method which uses the ``yield`` statement (see\n section *The yield statement*) is called a *generator function*.\n Such a function, when called, always returns an iterator object\n which can be used to execute the body of the function: calling\n the iterator\'s ``__next__()`` method will cause the function to\n execute until it provides a value using the ``yield`` statement.\n When the function executes a ``return`` statement or falls off\n the end, a ``StopIteration`` exception is raised and the\n iterator will have reached the end of the set of values to be\n returned.\n\n Built-in functions\n A built-in function object is a wrapper around a C function.\n Examples of built-in functions are ``len()`` and ``math.sin()``\n (``math`` is a standard built-in module). The number and type of\n the arguments are determined by the C function. Special read-\n only attributes: ``__doc__`` is the function\'s documentation\n string, or ``None`` if unavailable; ``__name__`` is the\n function\'s name; ``__self__`` is set to ``None`` (but see the\n next item); ``__module__`` is the name of the module the\n function was defined in or ``None`` if unavailable.\n\n Built-in methods\n This is really a different disguise of a built-in function, this\n time containing an object passed to the C function as an\n implicit extra argument. An example of a built-in method is\n ``alist.append()``, assuming *alist* is a list object. In this\n case, the special read-only attribute ``__self__`` is set to the\n object denoted by *list*.\n\n Classes\n Classes are callable. These objects normally act as factories\n for new instances of themselves, but variations are possible for\n class types that override ``__new__()``. The arguments of the\n call are passed to ``__new__()`` and, in the typical case, to\n ``__init__()`` to initialize the new instance.\n\n Class Instances\n Instances of arbitrary classes can be made callable by defining\n a ``__call__()`` method in their class.\n\nModules\n Modules are imported by the ``import`` statement (see section *The\n import statement*). A module object has a namespace implemented by\n a dictionary object (this is the dictionary referenced by the\n __globals__ attribute of functions defined in the module).\n Attribute references are translated to lookups in this dictionary,\n e.g., ``m.x`` is equivalent to ``m.__dict__["x"]``. A module object\n does not contain the code object used to initialize the module\n (since it isn\'t needed once the initialization is done).\n\n Attribute assignment updates the module\'s namespace dictionary,\n e.g., ``m.x = 1`` is equivalent to ``m.__dict__["x"] = 1``.\n\n Special read-only attribute: ``__dict__`` is the module\'s namespace\n as a dictionary object.\n\n Predefined (writable) attributes: ``__name__`` is the module\'s\n name; ``__doc__`` is the module\'s documentation string, or ``None``\n if unavailable; ``__file__`` is the pathname of the file from which\n the module was loaded, if it was loaded from a file. The\n ``__file__`` attribute is not present for C modules that are\n statically linked into the interpreter; for extension modules\n loaded dynamically from a shared library, it is the pathname of the\n shared library file.\n\nCustom classes\n Custon class types are typically created by class definitions (see\n section *Class definitions*). A class has a namespace implemented\n by a dictionary object. Class attribute references are translated\n to lookups in this dictionary, e.g., ``C.x`` is translated to\n ``C.__dict__["x"]`` (although there are a number of hooks which\n allow for other means of locating attributes). When the attribute\n name is not found there, the attribute search continues in the base\n classes. This search of the base classes uses the C3 method\n resolution order which behaves correctly even in the presence of\n \'diamond\' inheritance structures where there are multiple\n inheritance paths leading back to a common ancestor. Additional\n details on the C3 MRO used by Python can be found in the\n documentation accompanying the 2.3 release at\n http://www.python.org/download/releases/2.3/mro/.\n\n When a class attribute reference (for class ``C``, say) would yield\n a class method object, it is transformed into an instance method\n object whose ``__self__`` attributes is ``C``. When it would yield\n a static method object, it is transformed into the object wrapped\n by the static method object. See section *Implementing Descriptors*\n for another way in which attributes retrieved from a class may\n differ from those actually contained in its ``__dict__``.\n\n Class attribute assignments update the class\'s dictionary, never\n the dictionary of a base class.\n\n A class object can be called (see above) to yield a class instance\n (see below).\n\n Special attributes: ``__name__`` is the class name; ``__module__``\n is the module name in which the class was defined; ``__dict__`` is\n the dictionary containing the class\'s namespace; ``__bases__`` is a\n tuple (possibly empty or a singleton) containing the base classes,\n in the order of their occurrence in the base class list;\n ``__doc__`` is the class\'s documentation string, or None if\n undefined.\n\nClass instances\n A class instance is created by calling a class object (see above).\n A class instance has a namespace implemented as a dictionary which\n is the first place in which attribute references are searched.\n When an attribute is not found there, and the instance\'s class has\n an attribute by that name, the search continues with the class\n attributes. If a class attribute is found that is a user-defined\n function object, it is transformed into an instance method object\n whose ``__self__`` attribute is the instance. Static method and\n class method objects are also transformed; see above under\n "Classes". See section *Implementing Descriptors* for another way\n in which attributes of a class retrieved via its instances may\n differ from the objects actually stored in the class\'s\n ``__dict__``. If no class attribute is found, and the object\'s\n class has a ``__getattr__()`` method, that is called to satisfy the\n lookup.\n\n Attribute assignments and deletions update the instance\'s\n dictionary, never a class\'s dictionary. If the class has a\n ``__setattr__()`` or ``__delattr__()`` method, this is called\n instead of updating the instance dictionary directly.\n\n Class instances can pretend to be numbers, sequences, or mappings\n if they have methods with certain special names. See section\n *Special method names*.\n\n Special attributes: ``__dict__`` is the attribute dictionary;\n ``__class__`` is the instance\'s class.\n\nFiles\n A file object represents an open file. File objects are created by\n the ``open()`` built-in function, and also by ``os.popen()``,\n ``os.fdopen()``, and the ``makefile()`` method of socket objects\n (and perhaps by other functions or methods provided by extension\n modules). The objects ``sys.stdin``, ``sys.stdout`` and\n ``sys.stderr`` are initialized to file objects corresponding to the\n interpreter\'s standard input, output and error streams. See *File\n Objects* for complete documentation of file objects.\n\nInternal types\n A few types used internally by the interpreter are exposed to the\n user. Their definitions may change with future versions of the\n interpreter, but they are mentioned here for completeness.\n\n Code objects\n Code objects represent *byte-compiled* executable Python code,\n or *bytecode*. The difference between a code object and a\n function object is that the function object contains an explicit\n reference to the function\'s globals (the module in which it was\n defined), while a code object contains no context; also the\n default argument values are stored in the function object, not\n in the code object (because they represent values calculated at\n run-time). Unlike function objects, code objects are immutable\n and contain no references (directly or indirectly) to mutable\n objects.\n\n Special read-only attributes: ``co_name`` gives the function\n name; ``co_argcount`` is the number of positional arguments\n (including arguments with default values); ``co_nlocals`` is the\n number of local variables used by the function (including\n arguments); ``co_varnames`` is a tuple containing the names of\n the local variables (starting with the argument names);\n ``co_cellvars`` is a tuple containing the names of local\n variables that are referenced by nested functions;\n ``co_freevars`` is a tuple containing the names of free\n variables; ``co_code`` is a string representing the sequence of\n bytecode instructions; ``co_consts`` is a tuple containing the\n literals used by the bytecode; ``co_names`` is a tuple\n containing the names used by the bytecode; ``co_filename`` is\n the filename from which the code was compiled;\n ``co_firstlineno`` is the first line number of the function;\n ``co_lnotab`` is a string encoding the mapping from bytecode\n offsets to line numbers (for details see the source code of the\n interpreter); ``co_stacksize`` is the required stack size\n (including local variables); ``co_flags`` is an integer encoding\n a number of flags for the interpreter.\n\n The following flag bits are defined for ``co_flags``: bit\n ``0x04`` is set if the function uses the ``*arguments`` syntax\n to accept an arbitrary number of positional arguments; bit\n ``0x08`` is set if the function uses the ``**keywords`` syntax\n to accept arbitrary keyword arguments; bit ``0x20`` is set if\n the function is a generator.\n\n Future feature declarations (``from __future__ import\n division``) also use bits in ``co_flags`` to indicate whether a\n code object was compiled with a particular feature enabled: bit\n ``0x2000`` is set if the function was compiled with future\n division enabled; bits ``0x10`` and ``0x1000`` were used in\n earlier versions of Python.\n\n Other bits in ``co_flags`` are reserved for internal use.\n\n If a code object represents a function, the first item in\n ``co_consts`` is the documentation string of the function, or\n ``None`` if undefined.\n\n Frame objects\n Frame objects represent execution frames. They may occur in\n traceback objects (see below).\n\n Special read-only attributes: ``f_back`` is to the previous\n stack frame (towards the caller), or ``None`` if this is the\n bottom stack frame; ``f_code`` is the code object being executed\n in this frame; ``f_locals`` is the dictionary used to look up\n local variables; ``f_globals`` is used for global variables;\n ``f_builtins`` is used for built-in (intrinsic) names;\n ``f_lasti`` gives the precise instruction (this is an index into\n the bytecode string of the code object).\n\n Special writable attributes: ``f_trace``, if not ``None``, is a\n function called at the start of each source code line (this is\n used by the debugger); ``f_lineno`` is the current line number\n of the frame --- writing to this from within a trace function\n jumps to the given line (only for the bottom-most frame). A\n debugger can implement a Jump command (aka Set Next Statement)\n by writing to f_lineno.\n\n Traceback objects\n Traceback objects represent a stack trace of an exception. A\n traceback object is created when an exception occurs. When the\n search for an exception handler unwinds the execution stack, at\n each unwound level a traceback object is inserted in front of\n the current traceback. When an exception handler is entered,\n the stack trace is made available to the program. (See section\n *The try statement*.) It is accessible as the third item of the\n tuple returned by ``sys.exc_info()``. When the program contains\n no suitable handler, the stack trace is written (nicely\n formatted) to the standard error stream; if the interpreter is\n interactive, it is also made available to the user as\n ``sys.last_traceback``.\n\n Special read-only attributes: ``tb_next`` is the next level in\n the stack trace (towards the frame where the exception\n occurred), or ``None`` if there is no next level; ``tb_frame``\n points to the execution frame of the current level;\n ``tb_lineno`` gives the line number where the exception\n occurred; ``tb_lasti`` indicates the precise instruction. The\n line number and last instruction in the traceback may differ\n from the line number of its frame object if the exception\n occurred in a ``try`` statement with no matching except clause\n or with a finally clause.\n\n Slice objects\n Slice objects are used to represent slices for ``__getitem__()``\n methods. They are also created by the built-in ``slice()``\n function.\n\n Special read-only attributes: ``start`` is the lower bound;\n ``stop`` is the upper bound; ``step`` is the step value; each is\n ``None`` if omitted. These attributes can have any type.\n\n Slice objects support one method:\n\n slice.indices(self, length)\n\n This method takes a single integer argument *length* and\n computes information about the slice that the slice object\n would describe if applied to a sequence of *length* items.\n It returns a tuple of three integers; respectively these are\n the *start* and *stop* indices and the *step* or stride\n length of the slice. Missing or out-of-bounds indices are\n handled in a manner consistent with regular slices.\n\n Static method objects\n Static method objects provide a way of defeating the\n transformation of function objects to method objects described\n above. A static method object is a wrapper around any other\n object, usually a user-defined method object. When a static\n method object is retrieved from a class or a class instance, the\n object actually returned is the wrapped object, which is not\n subject to any further transformation. Static method objects are\n not themselves callable, although the objects they wrap usually\n are. Static method objects are created by the built-in\n ``staticmethod()`` constructor.\n\n Class method objects\n A class method object, like a static method object, is a wrapper\n around another object that alters the way in which that object\n is retrieved from classes and class instances. The behaviour of\n class method objects upon such retrieval is described above,\n under "User-defined methods". Class method objects are created\n by the built-in ``classmethod()`` constructor.\n', + 'try': '\nThe ``try`` statement\n*********************\n\nThe ``try`` statement specifies exception handlers and/or cleanup code\nfor a group of statements:\n\n try_stmt ::= try1_stmt | try2_stmt\n try1_stmt ::= "try" ":" suite\n ("except" [expression ["as" target]] ":" suite)+\n ["else" ":" suite]\n ["finally" ":" suite]\n try2_stmt ::= "try" ":" suite\n "finally" ":" suite\n\nThe ``except`` clause(s) specify one or more exception handlers. When\nno exception occurs in the ``try`` clause, no exception handler is\nexecuted. When an exception occurs in the ``try`` suite, a search for\nan exception handler is started. This search inspects the except\nclauses in turn until one is found that matches the exception. An\nexpression-less except clause, if present, must be last; it matches\nany exception. For an except clause with an expression, that\nexpression is evaluated, and the clause matches the exception if the\nresulting object is "compatible" with the exception. An object is\ncompatible with an exception if it is the class or a base class of the\nexception object or a tuple containing an item compatible with the\nexception.\n\nIf no except clause matches the exception, the search for an exception\nhandler continues in the surrounding code and on the invocation stack.\n[1]\n\nIf the evaluation of an expression in the header of an except clause\nraises an exception, the original search for a handler is canceled and\na search starts for the new exception in the surrounding code and on\nthe call stack (it is treated as if the entire ``try`` statement\nraised the exception).\n\nWhen a matching except clause is found, the exception is assigned to\nthe target specified after the ``as`` keyword in that except clause,\nif present, and the except clause\'s suite is executed. All except\nclauses must have an executable block. When the end of this block is\nreached, execution continues normally after the entire try statement.\n(This means that if two nested handlers exist for the same exception,\nand the exception occurs in the try clause of the inner handler, the\nouter handler will not handle the exception.)\n\nWhen an exception has been assigned using ``as target``, it is cleared\nat the end of the except clause. This is as if\n\n except E as N:\n foo\n\nwas translated to\n\n except E as N:\n try:\n foo\n finally:\n del N\n\nThis means the exception must be assigned to a different name to be\nable to refer to it after the except clause. Exceptions are cleared\nbecause with the traceback attached to them, they form a reference\ncycle with the stack frame, keeping all locals in that frame alive\nuntil the next garbage collection occurs.\n\nBefore an except clause\'s suite is executed, details about the\nexception are stored in the ``sys`` module and can be access via\n``sys.exc_info()``. ``sys.exc_info()`` returns a 3-tuple consisting of\nthe exception class, the exception instance and a traceback object\n(see section *The standard type hierarchy*) identifying the point in\nthe program where the exception occurred. ``sys.exc_info()`` values\nare restored to their previous values (before the call) when returning\nfrom a function that handled an exception.\n\nThe optional ``else`` clause is executed if and when control flows off\nthe end of the ``try`` clause. [2] Exceptions in the ``else`` clause\nare not handled by the preceding ``except`` clauses.\n\nIf ``finally`` is present, it specifies a \'cleanup\' handler. The\n``try`` clause is executed, including any ``except`` and ``else``\nclauses. If an exception occurs in any of the clauses and is not\nhandled, the exception is temporarily saved. The ``finally`` clause is\nexecuted. If there is a saved exception, it is re-raised at the end\nof the ``finally`` clause. If the ``finally`` clause raises another\nexception or executes a ``return`` or ``break`` statement, the saved\nexception is lost. The exception information is not available to the\nprogram during execution of the ``finally`` clause.\n\nWhen a ``return``, ``break`` or ``continue`` statement is executed in\nthe ``try`` suite of a ``try``...``finally`` statement, the\n``finally`` clause is also executed \'on the way out.\' A ``continue``\nstatement is illegal in the ``finally`` clause. (The reason is a\nproblem with the current implementation --- this restriction may be\nlifted in the future).\n\nAdditional information on exceptions can be found in section\n*Exceptions*, and information on using the ``raise`` statement to\ngenerate exceptions may be found in section *The raise statement*.\n', + 'types': '\nThe standard type hierarchy\n***************************\n\nBelow is a list of the types that are built into Python. Extension\nmodules (written in C, Java, or other languages, depending on the\nimplementation) can define additional types. Future versions of\nPython may add types to the type hierarchy (e.g., rational numbers,\nefficiently stored arrays of integers, etc.), although such additions\nwill often be provided via the standard library instead.\n\nSome of the type descriptions below contain a paragraph listing\n\'special attributes.\' These are attributes that provide access to the\nimplementation and are not intended for general use. Their definition\nmay change in the future.\n\nNone\n This type has a single value. There is a single object with this\n value. This object is accessed through the built-in name ``None``.\n It is used to signify the absence of a value in many situations,\n e.g., it is returned from functions that don\'t explicitly return\n anything. Its truth value is false.\n\nNotImplemented\n This type has a single value. There is a single object with this\n value. This object is accessed through the built-in name\n ``NotImplemented``. Numeric methods and rich comparison methods may\n return this value if they do not implement the operation for the\n operands provided. (The interpreter will then try the reflected\n operation, or some other fallback, depending on the operator.) Its\n truth value is true.\n\nEllipsis\n This type has a single value. There is a single object with this\n value. This object is accessed through the literal ``...`` or the\n built-in name ``Ellipsis``. Its truth value is true.\n\n``numbers.Number``\n These are created by numeric literals and returned as results by\n arithmetic operators and arithmetic built-in functions. Numeric\n objects are immutable; once created their value never changes.\n Python numbers are of course strongly related to mathematical\n numbers, but subject to the limitations of numerical representation\n in computers.\n\n Python distinguishes between integers, floating point numbers, and\n complex numbers:\n\n ``numbers.Integral``\n These represent elements from the mathematical set of integers\n (positive and negative).\n\n There are two types of integers:\n\n Integers (``int``)\n\n These represent numbers in an unlimited range, subject to\n available (virtual) memory only. For the purpose of shift\n and mask operations, a binary representation is assumed, and\n negative numbers are represented in a variant of 2\'s\n complement which gives the illusion of an infinite string of\n sign bits extending to the left.\n\n Booleans (``bool``)\n These represent the truth values False and True. The two\n objects representing the values False and True are the only\n Boolean objects. The Boolean type is a subtype of the integer\n type, and Boolean values behave like the values 0 and 1,\n respectively, in almost all contexts, the exception being\n that when converted to a string, the strings ``"False"`` or\n ``"True"`` are returned, respectively.\n\n The rules for integer representation are intended to give the\n most meaningful interpretation of shift and mask operations\n involving negative integers.\n\n ``numbers.Real`` (``float``)\n These represent machine-level double precision floating point\n numbers. You are at the mercy of the underlying machine\n architecture (and C or Java implementation) for the accepted\n range and handling of overflow. Python does not support single-\n precision floating point numbers; the savings in processor and\n memory usage that are usually the reason for using these is\n dwarfed by the overhead of using objects in Python, so there is\n no reason to complicate the language with two kinds of floating\n point numbers.\n\n ``numbers.Complex`` (``complex``)\n These represent complex numbers as a pair of machine-level\n double precision floating point numbers. The same caveats apply\n as for floating point numbers. The real and imaginary parts of a\n complex number ``z`` can be retrieved through the read-only\n attributes ``z.real`` and ``z.imag``.\n\nSequences\n These represent finite ordered sets indexed by non-negative\n numbers. The built-in function ``len()`` returns the number of\n items of a sequence. When the length of a sequence is *n*, the\n index set contains the numbers 0, 1, ..., *n*-1. Item *i* of\n sequence *a* is selected by ``a[i]``.\n\n Sequences also support slicing: ``a[i:j]`` selects all items with\n index *k* such that *i* ``<=`` *k* ``<`` *j*. When used as an\n expression, a slice is a sequence of the same type. This implies\n that the index set is renumbered so that it starts at 0.\n\n Some sequences also support "extended slicing" with a third "step"\n parameter: ``a[i:j:k]`` selects all items of *a* with index *x*\n where ``x = i + n*k``, *n* ``>=`` ``0`` and *i* ``<=`` *x* ``<``\n *j*.\n\n Sequences are distinguished according to their mutability:\n\n Immutable sequences\n An object of an immutable sequence type cannot change once it is\n created. (If the object contains references to other objects,\n these other objects may be mutable and may be changed; however,\n the collection of objects directly referenced by an immutable\n object cannot change.)\n\n The following types are immutable sequences:\n\n Strings\n The items of a string object are Unicode code units. A\n Unicode code unit is represented by a string object of one\n item and can hold either a 16-bit or 32-bit value\n representing a Unicode ordinal (the maximum value for the\n ordinal is given in ``sys.maxunicode``, and depends on how\n Python is configured at compile time). Surrogate pairs may\n be present in the Unicode object, and will be reported as two\n separate items. The built-in functions ``chr()`` and\n ``ord()`` convert between code units and nonnegative integers\n representing the Unicode ordinals as defined in the Unicode\n Standard 3.0. Conversion from and to other encodings are\n possible through the string method ``encode()``.\n\n Tuples\n The items of a tuple are arbitrary Python objects. Tuples of\n two or more items are formed by comma-separated lists of\n expressions. A tuple of one item (a \'singleton\') can be\n formed by affixing a comma to an expression (an expression by\n itself does not create a tuple, since parentheses must be\n usable for grouping of expressions). An empty tuple can be\n formed by an empty pair of parentheses.\n\n Bytes\n A bytes object is an immutable array. The items are 8-bit\n bytes, represented by integers in the range 0 <= x < 256.\n Bytes literals (like ``b\'abc\'`` and the built-in function\n ``bytes()`` can be used to construct bytes objects. Also,\n bytes objects can be decoded to strings via the ``decode()``\n method.\n\n Mutable sequences\n Mutable sequences can be changed after they are created. The\n subscription and slicing notations can be used as the target of\n assignment and ``del`` (delete) statements.\n\n There are currently two intrinsic mutable sequence types:\n\n Lists\n The items of a list are arbitrary Python objects. Lists are\n formed by placing a comma-separated list of expressions in\n square brackets. (Note that there are no special cases needed\n to form lists of length 0 or 1.)\n\n Byte Arrays\n A bytearray object is a mutable array. They are created by\n the built-in ``bytearray()`` constructor. Aside from being\n mutable (and hence unhashable), byte arrays otherwise provide\n the same interface and functionality as immutable bytes\n objects.\n\n The extension module ``array`` provides an additional example of\n a mutable sequence type, as does the ``collections`` module.\n\nSet types\n These represent unordered, finite sets of unique, immutable\n objects. As such, they cannot be indexed by any subscript. However,\n they can be iterated over, and the built-in function ``len()``\n returns the number of items in a set. Common uses for sets are fast\n membership testing, removing duplicates from a sequence, and\n computing mathematical operations such as intersection, union,\n difference, and symmetric difference.\n\n For set elements, the same immutability rules apply as for\n dictionary keys. Note that numeric types obey the normal rules for\n numeric comparison: if two numbers compare equal (e.g., ``1`` and\n ``1.0``), only one of them can be contained in a set.\n\n There are currently two intrinsic set types:\n\n Sets\n These represent a mutable set. They are created by the built-in\n ``set()`` constructor and can be modified afterwards by several\n methods, such as ``add()``.\n\n Frozen sets\n These represent an immutable set. They are created by the\n built-in ``frozenset()`` constructor. As a frozenset is\n immutable and *hashable*, it can be used again as an element of\n another set, or as a dictionary key.\n\nMappings\n These represent finite sets of objects indexed by arbitrary index\n sets. The subscript notation ``a[k]`` selects the item indexed by\n ``k`` from the mapping ``a``; this can be used in expressions and\n as the target of assignments or ``del`` statements. The built-in\n function ``len()`` returns the number of items in a mapping.\n\n There is currently a single intrinsic mapping type:\n\n Dictionaries\n These represent finite sets of objects indexed by nearly\n arbitrary values. The only types of values not acceptable as\n keys are values containing lists or dictionaries or other\n mutable types that are compared by value rather than by object\n identity, the reason being that the efficient implementation of\n dictionaries requires a key\'s hash value to remain constant.\n Numeric types used for keys obey the normal rules for numeric\n comparison: if two numbers compare equal (e.g., ``1`` and\n ``1.0``) then they can be used interchangeably to index the same\n dictionary entry.\n\n Dictionaries are mutable; they can be created by the ``{...}``\n notation (see section *Dictionary displays*).\n\n The extension modules ``dbm.ndbm`` and ``dbm.gnu`` provide\n additional examples of mapping types, as does the\n ``collections`` module.\n\nCallable types\n These are the types to which the function call operation (see\n section *Calls*) can be applied:\n\n User-defined functions\n A user-defined function object is created by a function\n definition (see section *Function definitions*). It should be\n called with an argument list containing the same number of items\n as the function\'s formal parameter list.\n\n Special attributes:\n\n +---------------------------+---------------------------------+-------------+\n | Attribute | Meaning | |\n +===========================+=================================+=============+\n | ``__doc__`` | The function\'s documentation | Writable |\n | | string, or ``None`` if | |\n | | unavailable | |\n +---------------------------+---------------------------------+-------------+\n | ``__name__`` | The function\'s name | Writable |\n +---------------------------+---------------------------------+-------------+\n | ``__module__`` | The name of the module the | Writable |\n | | function was defined in, or | |\n | | ``None`` if unavailable. | |\n +---------------------------+---------------------------------+-------------+\n | ``__defaults__`` | A tuple containing default | Writable |\n | | argument values for those | |\n | | arguments that have defaults, | |\n | | or ``None`` if no arguments | |\n | | have a default value | |\n +---------------------------+---------------------------------+-------------+\n | ``__code__`` | The code object representing | Writable |\n | | the compiled function body. | |\n +---------------------------+---------------------------------+-------------+\n | ``__globals__`` | A reference to the dictionary | Read-only |\n | | that holds the function\'s | |\n | | global variables --- the global | |\n | | namespace of the module in | |\n | | which the function was defined. | |\n +---------------------------+---------------------------------+-------------+\n | ``__dict__`` | The namespace supporting | Writable |\n | | arbitrary function attributes. | |\n +---------------------------+---------------------------------+-------------+\n | ``__closure__`` | ``None`` or a tuple of cells | Read-only |\n | | that contain bindings for the | |\n | | function\'s free variables. | |\n +---------------------------+---------------------------------+-------------+\n | ``__annotations__`` | A dict containing annotations | Writable |\n | | of parameters. The keys of the | |\n | | dict are the parameter names, | |\n | | or ``\'return\'`` for the return | |\n | | annotation, if provided. | |\n +---------------------------+---------------------------------+-------------+\n | ``__kwdefaults__`` | A dict containing defaults for | Writable |\n | | keyword-only parameters. | |\n +---------------------------+---------------------------------+-------------+\n\n Most of the attributes labelled "Writable" check the type of the\n assigned value.\n\n Function objects also support getting and setting arbitrary\n attributes, which can be used, for example, to attach metadata\n to functions. Regular attribute dot-notation is used to get and\n set such attributes. *Note that the current implementation only\n supports function attributes on user-defined functions. Function\n attributes on built-in functions may be supported in the\n future.*\n\n Additional information about a function\'s definition can be\n retrieved from its code object; see the description of internal\n types below.\n\n Instance methods\n An instance method object combines a class, a class instance and\n any callable object (normally a user-defined function).\n\n Special read-only attributes: ``__self__`` is the class instance\n object, ``__func__`` is the function object; ``__doc__`` is the\n method\'s documentation (same as ``__func__.__doc__``);\n ``__name__`` is the method name (same as ``__func__.__name__``);\n ``__module__`` is the name of the module the method was defined\n in, or ``None`` if unavailable.\n\n Methods also support accessing (but not setting) the arbitrary\n function attributes on the underlying function object.\n\n User-defined method objects may be created when getting an\n attribute of a class (perhaps via an instance of that class), if\n that attribute is a user-defined function object or a class\n method object.\n\n When an instance method object is created by retrieving a user-\n defined function object from a class via one of its instances,\n its ``__self__`` attribute is the instance, and the method\n object is said to be bound. The new method\'s ``__func__``\n attribute is the original function object.\n\n When a user-defined method object is created by retrieving\n another method object from a class or instance, the behaviour is\n the same as for a function object, except that the ``__func__``\n attribute of the new instance is not the original method object\n but its ``__func__`` attribute.\n\n When an instance method object is created by retrieving a class\n method object from a class or instance, its ``__self__``\n attribute is the class itself, and its ``__func__`` attribute is\n the function object underlying the class method.\n\n When an instance method object is called, the underlying\n function (``__func__``) is called, inserting the class instance\n (``__self__``) in front of the argument list. For instance,\n when ``C`` is a class which contains a definition for a function\n ``f()``, and ``x`` is an instance of ``C``, calling ``x.f(1)``\n is equivalent to calling ``C.f(x, 1)``.\n\n When an instance method object is derived from a class method\n object, the "class instance" stored in ``__self__`` will\n actually be the class itself, so that calling either ``x.f(1)``\n or ``C.f(1)`` is equivalent to calling ``f(C,1)`` where ``f`` is\n the underlying function.\n\n Note that the transformation from function object to instance\n method object happens each time the attribute is retrieved from\n the instance. In some cases, a fruitful optimization is to\n assign the attribute to a local variable and call that local\n variable. Also notice that this transformation only happens for\n user-defined functions; other callable objects (and all non-\n callable objects) are retrieved without transformation. It is\n also important to note that user-defined functions which are\n attributes of a class instance are not converted to bound\n methods; this *only* happens when the function is an attribute\n of the class.\n\n Generator functions\n A function or method which uses the ``yield`` statement (see\n section *The yield statement*) is called a *generator function*.\n Such a function, when called, always returns an iterator object\n which can be used to execute the body of the function: calling\n the iterator\'s ``__next__()`` method will cause the function to\n execute until it provides a value using the ``yield`` statement.\n When the function executes a ``return`` statement or falls off\n the end, a ``StopIteration`` exception is raised and the\n iterator will have reached the end of the set of values to be\n returned.\n\n Built-in functions\n A built-in function object is a wrapper around a C function.\n Examples of built-in functions are ``len()`` and ``math.sin()``\n (``math`` is a standard built-in module). The number and type of\n the arguments are determined by the C function. Special read-\n only attributes: ``__doc__`` is the function\'s documentation\n string, or ``None`` if unavailable; ``__name__`` is the\n function\'s name; ``__self__`` is set to ``None`` (but see the\n next item); ``__module__`` is the name of the module the\n function was defined in or ``None`` if unavailable.\n\n Built-in methods\n This is really a different disguise of a built-in function, this\n time containing an object passed to the C function as an\n implicit extra argument. An example of a built-in method is\n ``alist.append()``, assuming *alist* is a list object. In this\n case, the special read-only attribute ``__self__`` is set to the\n object denoted by *alist*.\n\n Classes\n Classes are callable. These objects normally act as factories\n for new instances of themselves, but variations are possible for\n class types that override ``__new__()``. The arguments of the\n call are passed to ``__new__()`` and, in the typical case, to\n ``__init__()`` to initialize the new instance.\n\n Class Instances\n Instances of arbitrary classes can be made callable by defining\n a ``__call__()`` method in their class.\n\nModules\n Modules are imported by the ``import`` statement (see section *The\n import statement*). A module object has a namespace implemented by\n a dictionary object (this is the dictionary referenced by the\n __globals__ attribute of functions defined in the module).\n Attribute references are translated to lookups in this dictionary,\n e.g., ``m.x`` is equivalent to ``m.__dict__["x"]``. A module object\n does not contain the code object used to initialize the module\n (since it isn\'t needed once the initialization is done).\n\n Attribute assignment updates the module\'s namespace dictionary,\n e.g., ``m.x = 1`` is equivalent to ``m.__dict__["x"] = 1``.\n\n Special read-only attribute: ``__dict__`` is the module\'s namespace\n as a dictionary object.\n\n **CPython implementation detail:** Because of the way CPython\n clears module dictionaries, the module dictionary will be cleared\n when the module falls out of scope even if the dictionary still has\n live references. To avoid this, copy the dictionary or keep the\n module around while using its dictionary directly.\n\n Predefined (writable) attributes: ``__name__`` is the module\'s\n name; ``__doc__`` is the module\'s documentation string, or ``None``\n if unavailable; ``__file__`` is the pathname of the file from which\n the module was loaded, if it was loaded from a file. The\n ``__file__`` attribute is not present for C modules that are\n statically linked into the interpreter; for extension modules\n loaded dynamically from a shared library, it is the pathname of the\n shared library file.\n\nCustom classes\n Custom class types are typically created by class definitions (see\n section *Class definitions*). A class has a namespace implemented\n by a dictionary object. Class attribute references are translated\n to lookups in this dictionary, e.g., ``C.x`` is translated to\n ``C.__dict__["x"]`` (although there are a number of hooks which\n allow for other means of locating attributes). When the attribute\n name is not found there, the attribute search continues in the base\n classes. This search of the base classes uses the C3 method\n resolution order which behaves correctly even in the presence of\n \'diamond\' inheritance structures where there are multiple\n inheritance paths leading back to a common ancestor. Additional\n details on the C3 MRO used by Python can be found in the\n documentation accompanying the 2.3 release at\n http://www.python.org/download/releases/2.3/mro/.\n\n When a class attribute reference (for class ``C``, say) would yield\n a class method object, it is transformed into an instance method\n object whose ``__self__`` attributes is ``C``. When it would yield\n a static method object, it is transformed into the object wrapped\n by the static method object. See section *Implementing Descriptors*\n for another way in which attributes retrieved from a class may\n differ from those actually contained in its ``__dict__``.\n\n Class attribute assignments update the class\'s dictionary, never\n the dictionary of a base class.\n\n A class object can be called (see above) to yield a class instance\n (see below).\n\n Special attributes: ``__name__`` is the class name; ``__module__``\n is the module name in which the class was defined; ``__dict__`` is\n the dictionary containing the class\'s namespace; ``__bases__`` is a\n tuple (possibly empty or a singleton) containing the base classes,\n in the order of their occurrence in the base class list;\n ``__doc__`` is the class\'s documentation string, or None if\n undefined.\n\nClass instances\n A class instance is created by calling a class object (see above).\n A class instance has a namespace implemented as a dictionary which\n is the first place in which attribute references are searched.\n When an attribute is not found there, and the instance\'s class has\n an attribute by that name, the search continues with the class\n attributes. If a class attribute is found that is a user-defined\n function object, it is transformed into an instance method object\n whose ``__self__`` attribute is the instance. Static method and\n class method objects are also transformed; see above under\n "Classes". See section *Implementing Descriptors* for another way\n in which attributes of a class retrieved via its instances may\n differ from the objects actually stored in the class\'s\n ``__dict__``. If no class attribute is found, and the object\'s\n class has a ``__getattr__()`` method, that is called to satisfy the\n lookup.\n\n Attribute assignments and deletions update the instance\'s\n dictionary, never a class\'s dictionary. If the class has a\n ``__setattr__()`` or ``__delattr__()`` method, this is called\n instead of updating the instance dictionary directly.\n\n Class instances can pretend to be numbers, sequences, or mappings\n if they have methods with certain special names. See section\n *Special method names*.\n\n Special attributes: ``__dict__`` is the attribute dictionary;\n ``__class__`` is the instance\'s class.\n\nI/O objects (also known as file objects)\n A *file object* represents an open file. Various shortcuts are\n available to create file objects: the ``open()`` built-in function,\n and also ``os.popen()``, ``os.fdopen()``, and the ``makefile()``\n method of socket objects (and perhaps by other functions or methods\n provided by extension modules).\n\n The objects ``sys.stdin``, ``sys.stdout`` and ``sys.stderr`` are\n initialized to file objects corresponding to the interpreter\'s\n standard input, output and error streams; they are all open in text\n mode and therefore follow the interface defined by the\n ``io.TextIOBase`` abstract class.\n\nInternal types\n A few types used internally by the interpreter are exposed to the\n user. Their definitions may change with future versions of the\n interpreter, but they are mentioned here for completeness.\n\n Code objects\n Code objects represent *byte-compiled* executable Python code,\n or *bytecode*. The difference between a code object and a\n function object is that the function object contains an explicit\n reference to the function\'s globals (the module in which it was\n defined), while a code object contains no context; also the\n default argument values are stored in the function object, not\n in the code object (because they represent values calculated at\n run-time). Unlike function objects, code objects are immutable\n and contain no references (directly or indirectly) to mutable\n objects.\n\n Special read-only attributes: ``co_name`` gives the function\n name; ``co_argcount`` is the number of positional arguments\n (including arguments with default values); ``co_nlocals`` is the\n number of local variables used by the function (including\n arguments); ``co_varnames`` is a tuple containing the names of\n the local variables (starting with the argument names);\n ``co_cellvars`` is a tuple containing the names of local\n variables that are referenced by nested functions;\n ``co_freevars`` is a tuple containing the names of free\n variables; ``co_code`` is a string representing the sequence of\n bytecode instructions; ``co_consts`` is a tuple containing the\n literals used by the bytecode; ``co_names`` is a tuple\n containing the names used by the bytecode; ``co_filename`` is\n the filename from which the code was compiled;\n ``co_firstlineno`` is the first line number of the function;\n ``co_lnotab`` is a string encoding the mapping from bytecode\n offsets to line numbers (for details see the source code of the\n interpreter); ``co_stacksize`` is the required stack size\n (including local variables); ``co_flags`` is an integer encoding\n a number of flags for the interpreter.\n\n The following flag bits are defined for ``co_flags``: bit\n ``0x04`` is set if the function uses the ``*arguments`` syntax\n to accept an arbitrary number of positional arguments; bit\n ``0x08`` is set if the function uses the ``**keywords`` syntax\n to accept arbitrary keyword arguments; bit ``0x20`` is set if\n the function is a generator.\n\n Future feature declarations (``from __future__ import\n division``) also use bits in ``co_flags`` to indicate whether a\n code object was compiled with a particular feature enabled: bit\n ``0x2000`` is set if the function was compiled with future\n division enabled; bits ``0x10`` and ``0x1000`` were used in\n earlier versions of Python.\n\n Other bits in ``co_flags`` are reserved for internal use.\n\n If a code object represents a function, the first item in\n ``co_consts`` is the documentation string of the function, or\n ``None`` if undefined.\n\n Frame objects\n Frame objects represent execution frames. They may occur in\n traceback objects (see below).\n\n Special read-only attributes: ``f_back`` is to the previous\n stack frame (towards the caller), or ``None`` if this is the\n bottom stack frame; ``f_code`` is the code object being executed\n in this frame; ``f_locals`` is the dictionary used to look up\n local variables; ``f_globals`` is used for global variables;\n ``f_builtins`` is used for built-in (intrinsic) names;\n ``f_lasti`` gives the precise instruction (this is an index into\n the bytecode string of the code object).\n\n Special writable attributes: ``f_trace``, if not ``None``, is a\n function called at the start of each source code line (this is\n used by the debugger); ``f_lineno`` is the current line number\n of the frame --- writing to this from within a trace function\n jumps to the given line (only for the bottom-most frame). A\n debugger can implement a Jump command (aka Set Next Statement)\n by writing to f_lineno.\n\n Traceback objects\n Traceback objects represent a stack trace of an exception. A\n traceback object is created when an exception occurs. When the\n search for an exception handler unwinds the execution stack, at\n each unwound level a traceback object is inserted in front of\n the current traceback. When an exception handler is entered,\n the stack trace is made available to the program. (See section\n *The try statement*.) It is accessible as the third item of the\n tuple returned by ``sys.exc_info()``. When the program contains\n no suitable handler, the stack trace is written (nicely\n formatted) to the standard error stream; if the interpreter is\n interactive, it is also made available to the user as\n ``sys.last_traceback``.\n\n Special read-only attributes: ``tb_next`` is the next level in\n the stack trace (towards the frame where the exception\n occurred), or ``None`` if there is no next level; ``tb_frame``\n points to the execution frame of the current level;\n ``tb_lineno`` gives the line number where the exception\n occurred; ``tb_lasti`` indicates the precise instruction. The\n line number and last instruction in the traceback may differ\n from the line number of its frame object if the exception\n occurred in a ``try`` statement with no matching except clause\n or with a finally clause.\n\n Slice objects\n Slice objects are used to represent slices for ``__getitem__()``\n methods. They are also created by the built-in ``slice()``\n function.\n\n Special read-only attributes: ``start`` is the lower bound;\n ``stop`` is the upper bound; ``step`` is the step value; each is\n ``None`` if omitted. These attributes can have any type.\n\n Slice objects support one method:\n\n slice.indices(self, length)\n\n This method takes a single integer argument *length* and\n computes information about the slice that the slice object\n would describe if applied to a sequence of *length* items.\n It returns a tuple of three integers; respectively these are\n the *start* and *stop* indices and the *step* or stride\n length of the slice. Missing or out-of-bounds indices are\n handled in a manner consistent with regular slices.\n\n Static method objects\n Static method objects provide a way of defeating the\n transformation of function objects to method objects described\n above. A static method object is a wrapper around any other\n object, usually a user-defined method object. When a static\n method object is retrieved from a class or a class instance, the\n object actually returned is the wrapped object, which is not\n subject to any further transformation. Static method objects are\n not themselves callable, although the objects they wrap usually\n are. Static method objects are created by the built-in\n ``staticmethod()`` constructor.\n\n Class method objects\n A class method object, like a static method object, is a wrapper\n around another object that alters the way in which that object\n is retrieved from classes and class instances. The behaviour of\n class method objects upon such retrieval is described above,\n under "User-defined methods". Class method objects are created\n by the built-in ``classmethod()`` constructor.\n', 'typesfunctions': '\nFunctions\n*********\n\nFunction objects are created by function definitions. The only\noperation on a function object is to call it: ``func(argument-list)``.\n\nThere are really two flavors of function objects: built-in functions\nand user-defined functions. Both support the same operation (to call\nthe function), but the implementation is different, hence the\ndifferent object types.\n\nSee *Function definitions* for more information.\n', - 'typesmapping': '\nMapping Types --- ``dict``\n**************************\n\nA *mapping* object maps *hashable* values to arbitrary objects.\nMappings are mutable objects. There is currently only one standard\nmapping type, the *dictionary*. (For other containers see the built\nin ``list``, ``set``, and ``tuple`` classes, and the ``collections``\nmodule.)\n\nA dictionary\'s keys are *almost* arbitrary values. Values that are\nnot *hashable*, that is, values containing lists, dictionaries or\nother mutable types (that are compared by value rather than by object\nidentity) may not be used as keys. Numeric types used for keys obey\nthe normal rules for numeric comparison: if two numbers compare equal\n(such as ``1`` and ``1.0``) then they can be used interchangeably to\nindex the same dictionary entry. (Note however, that since computers\nstore floating-point numbers as approximations it is usually unwise to\nuse them as dictionary keys.)\n\nDictionaries can be created by placing a comma-separated list of\n``key: value`` pairs within braces, for example: ``{\'jack\': 4098,\n\'sjoerd\': 4127}`` or ``{4098: \'jack\', 4127: \'sjoerd\'}``, or by the\n``dict`` constructor.\n\nclass class dict([arg])\n\n Return a new dictionary initialized from an optional positional\n argument or from a set of keyword arguments. If no arguments are\n given, return a new empty dictionary. If the positional argument\n *arg* is a mapping object, return a dictionary mapping the same\n keys to the same values as does the mapping object. Otherwise the\n positional argument must be a sequence, a container that supports\n iteration, or an iterator object. The elements of the argument\n must each also be of one of those kinds, and each must in turn\n contain exactly two objects. The first is used as a key in the new\n dictionary, and the second as the key\'s value. If a given key is\n seen more than once, the last value associated with it is retained\n in the new dictionary.\n\n If keyword arguments are given, the keywords themselves with their\n associated values are added as items to the dictionary. If a key\n is specified both in the positional argument and as a keyword\n argument, the value associated with the keyword is retained in the\n dictionary. For example, these all return a dictionary equal to\n ``{"one": 2, "two": 3}``:\n\n * ``dict(one=2, two=3)``\n\n * ``dict({\'one\': 2, \'two\': 3})``\n\n * ``dict(zip((\'one\', \'two\'), (2, 3)))``\n\n * ``dict([[\'two\', 3], [\'one\', 2]])``\n\n The first example only works for keys that are valid Python\n identifiers; the others work with any valid keys.\n\n These are the operations that dictionaries support (and therefore,\n custom mapping types should support too):\n\n len(d)\n\n Return the number of items in the dictionary *d*.\n\n d[key]\n\n Return the item of *d* with key *key*. Raises a ``KeyError`` if\n *key* is not in the map.\n\n If a subclass of dict defines a method ``__missing__()``, if the\n key *key* is not present, the ``d[key]`` operation calls that\n method with the key *key* as argument. The ``d[key]`` operation\n then returns or raises whatever is returned or raised by the\n ``__missing__(key)`` call if the key is not present. No other\n operations or methods invoke ``__missing__()``. If\n ``__missing__()`` is not defined, ``KeyError`` is raised.\n ``__missing__()`` must be a method; it cannot be an instance\n variable. For an example, see ``collections.defaultdict``.\n\n d[key] = value\n\n Set ``d[key]`` to *value*.\n\n del d[key]\n\n Remove ``d[key]`` from *d*. Raises a ``KeyError`` if *key* is\n not in the map.\n\n key in d\n\n Return ``True`` if *d* has a key *key*, else ``False``.\n\n key not in d\n\n Equivalent to ``not key in d``.\n\n iter(d)\n\n Return an iterator over the keys of the dictionary. This is a\n shortcut for ``iterkeys()``.\n\n clear()\n\n Remove all items from the dictionary.\n\n copy()\n\n Return a shallow copy of the dictionary.\n\n classmethod fromkeys(seq[, value])\n\n Create a new dictionary with keys from *seq* and values set to\n *value*.\n\n ``fromkeys()`` is a class method that returns a new dictionary.\n *value* defaults to ``None``.\n\n get(key[, default])\n\n Return the value for *key* if *key* is in the dictionary, else\n *default*. If *default* is not given, it defaults to ``None``,\n so that this method never raises a ``KeyError``.\n\n items()\n\n Return a new view of the dictionary\'s items (``(key, value)``\n pairs). See below for documentation of view objects.\n\n keys()\n\n Return a new view of the dictionary\'s keys. See below for\n documentation of view objects.\n\n pop(key[, default])\n\n If *key* is in the dictionary, remove it and return its value,\n else return *default*. If *default* is not given and *key* is\n not in the dictionary, a ``KeyError`` is raised.\n\n popitem()\n\n Remove and return an arbitrary ``(key, value)`` pair from the\n dictionary.\n\n ``popitem()`` is useful to destructively iterate over a\n dictionary, as often used in set algorithms. If the dictionary\n is empty, calling ``popitem()`` raises a ``KeyError``.\n\n setdefault(key[, default])\n\n If *key* is in the dictionary, return its value. If not, insert\n *key* with a value of *default* and return *default*. *default*\n defaults to ``None``.\n\n update([other])\n\n Update the dictionary with the key/value pairs from *other*,\n overwriting existing keys. Return ``None``.\n\n ``update()`` accepts either another dictionary object or an\n iterable of key/value pairs (as a tuple or other iterable of\n length two). If keyword arguments are specified, the\n dictionary is then is updated with those key/value pairs:\n ``d.update(red=1, blue=2)``.\n\n values()\n\n Return a new view of the dictionary\'s values. See below for\n documentation of view objects.\n\n\nDictionary view objects\n=======================\n\nThe objects returned by ``dict.keys()``, ``dict.values()`` and\n``dict.items()`` are *view objects*. They provide a dynamic view on\nthe dictionary\'s entries, which means that when the dictionary\nchanges, the view reflects these changes.\n\nDictionary views can be iterated over to yield their respective data,\nand support membership tests:\n\nlen(dictview)\n\n Return the number of entries in the dictionary.\n\niter(dictview)\n\n Return an iterator over the keys, values or items (represented as\n tuples of ``(key, value)``) in the dictionary.\n\n Keys and values are iterated over in an arbitrary order which is\n non-random, varies across Python implementations, and depends on\n the dictionary\'s history of insertions and deletions. If keys,\n values and items views are iterated over with no intervening\n modifications to the dictionary, the order of items will directly\n correspond. This allows the creation of ``(value, key)`` pairs\n using ``zip()``: ``pairs = zip(d.values(), d.keys())``. Another\n way to create the same list is ``pairs = [(v, k) for (k, v) in\n d.items()]``.\n\n Iterating views while adding or deleting entries in the dictionary\n may raise a ``RuntimeError`` or fail to iterate over all entries.\n\nx in dictview\n\n Return ``True`` if *x* is in the underlying dictionary\'s keys,\n values or items (in the latter case, *x* should be a ``(key,\n value)`` tuple).\n\nKeys views are set-like since their entries are unique and hashable.\nIf all values are hashable, so that (key, value) pairs are unique and\nhashable, then the items view is also set-like. (Values views are not\ntreated as set-like since the entries are generally not unique.) Then\nthese set operations are available ("other" refers either to another\nview or a set):\n\ndictview & other\n\n Return the intersection of the dictview and the other object as a\n new set.\n\ndictview | other\n\n Return the union of the dictview and the other object as a new set.\n\ndictview - other\n\n Return the difference between the dictview and the other object\n (all elements in *dictview* that aren\'t in *other*) as a new set.\n\ndictview ^ other\n\n Return the symmetric difference (all elements either in *dictview*\n or *other*, but not in both) of the dictview and the other object\n as a new set.\n\nAn example of dictionary view usage:\n\n >>> dishes = {\'eggs\': 2, \'sausage\': 1, \'bacon\': 1, \'spam\': 500}\n >>> keys = dishes.keys()\n >>> values = dishes.values()\n\n >>> # iteration\n >>> n = 0\n >>> for val in values:\n ... n += val\n >>> print(n)\n 504\n\n >>> # keys and values are iterated over in the same order\n >>> list(keys)\n [\'eggs\', \'bacon\', \'sausage\', \'spam\']\n >>> list(values)\n [2, 1, 1, 500]\n\n >>> # view objects are dynamic and reflect dict changes\n >>> del dishes[\'eggs\']\n >>> del dishes[\'sausage\']\n >>> list(keys)\n [\'spam\', \'bacon\']\n\n >>> # set operations\n >>> keys & {\'eggs\', \'bacon\', \'salad\'}\n {\'bacon\'}\n', + 'typesmapping': '\nMapping Types --- ``dict``\n**************************\n\nA *mapping* object maps *hashable* values to arbitrary objects.\nMappings are mutable objects. There is currently only one standard\nmapping type, the *dictionary*. (For other containers see the built\nin ``list``, ``set``, and ``tuple`` classes, and the ``collections``\nmodule.)\n\nA dictionary\'s keys are *almost* arbitrary values. Values that are\nnot *hashable*, that is, values containing lists, dictionaries or\nother mutable types (that are compared by value rather than by object\nidentity) may not be used as keys. Numeric types used for keys obey\nthe normal rules for numeric comparison: if two numbers compare equal\n(such as ``1`` and ``1.0``) then they can be used interchangeably to\nindex the same dictionary entry. (Note however, that since computers\nstore floating-point numbers as approximations it is usually unwise to\nuse them as dictionary keys.)\n\nDictionaries can be created by placing a comma-separated list of\n``key: value`` pairs within braces, for example: ``{\'jack\': 4098,\n\'sjoerd\': 4127}`` or ``{4098: \'jack\', 4127: \'sjoerd\'}``, or by the\n``dict`` constructor.\n\nclass class dict([arg])\n\n Return a new dictionary initialized from an optional positional\n argument or from a set of keyword arguments. If no arguments are\n given, return a new empty dictionary. If the positional argument\n *arg* is a mapping object, return a dictionary mapping the same\n keys to the same values as does the mapping object. Otherwise the\n positional argument must be a sequence, a container that supports\n iteration, or an iterator object. The elements of the argument\n must each also be of one of those kinds, and each must in turn\n contain exactly two objects. The first is used as a key in the new\n dictionary, and the second as the key\'s value. If a given key is\n seen more than once, the last value associated with it is retained\n in the new dictionary.\n\n If keyword arguments are given, the keywords themselves with their\n associated values are added as items to the dictionary. If a key\n is specified both in the positional argument and as a keyword\n argument, the value associated with the keyword is retained in the\n dictionary. For example, these all return a dictionary equal to\n ``{"one": 1, "two": 2}``:\n\n * ``dict(one=1, two=2)``\n\n * ``dict({\'one\': 1, \'two\': 2})``\n\n * ``dict(zip((\'one\', \'two\'), (1, 2)))``\n\n * ``dict([[\'two\', 2], [\'one\', 1]])``\n\n The first example only works for keys that are valid Python\n identifiers; the others work with any valid keys.\n\n These are the operations that dictionaries support (and therefore,\n custom mapping types should support too):\n\n len(d)\n\n Return the number of items in the dictionary *d*.\n\n d[key]\n\n Return the item of *d* with key *key*. Raises a ``KeyError`` if\n *key* is not in the map.\n\n If a subclass of dict defines a method ``__missing__()``, if the\n key *key* is not present, the ``d[key]`` operation calls that\n method with the key *key* as argument. The ``d[key]`` operation\n then returns or raises whatever is returned or raised by the\n ``__missing__(key)`` call if the key is not present. No other\n operations or methods invoke ``__missing__()``. If\n ``__missing__()`` is not defined, ``KeyError`` is raised.\n ``__missing__()`` must be a method; it cannot be an instance\n variable. For an example, see ``collections.defaultdict``.\n\n d[key] = value\n\n Set ``d[key]`` to *value*.\n\n del d[key]\n\n Remove ``d[key]`` from *d*. Raises a ``KeyError`` if *key* is\n not in the map.\n\n key in d\n\n Return ``True`` if *d* has a key *key*, else ``False``.\n\n key not in d\n\n Equivalent to ``not key in d``.\n\n iter(d)\n\n Return an iterator over the keys of the dictionary. This is a\n shortcut for ``iter(d.keys())``.\n\n clear()\n\n Remove all items from the dictionary.\n\n copy()\n\n Return a shallow copy of the dictionary.\n\n classmethod fromkeys(seq[, value])\n\n Create a new dictionary with keys from *seq* and values set to\n *value*.\n\n ``fromkeys()`` is a class method that returns a new dictionary.\n *value* defaults to ``None``.\n\n get(key[, default])\n\n Return the value for *key* if *key* is in the dictionary, else\n *default*. If *default* is not given, it defaults to ``None``,\n so that this method never raises a ``KeyError``.\n\n items()\n\n Return a new view of the dictionary\'s items (``(key, value)``\n pairs). See below for documentation of view objects.\n\n keys()\n\n Return a new view of the dictionary\'s keys. See below for\n documentation of view objects.\n\n pop(key[, default])\n\n If *key* is in the dictionary, remove it and return its value,\n else return *default*. If *default* is not given and *key* is\n not in the dictionary, a ``KeyError`` is raised.\n\n popitem()\n\n Remove and return an arbitrary ``(key, value)`` pair from the\n dictionary.\n\n ``popitem()`` is useful to destructively iterate over a\n dictionary, as often used in set algorithms. If the dictionary\n is empty, calling ``popitem()`` raises a ``KeyError``.\n\n setdefault(key[, default])\n\n If *key* is in the dictionary, return its value. If not, insert\n *key* with a value of *default* and return *default*. *default*\n defaults to ``None``.\n\n update([other])\n\n Update the dictionary with the key/value pairs from *other*,\n overwriting existing keys. Return ``None``.\n\n ``update()`` accepts either another dictionary object or an\n iterable of key/value pairs (as tuples or other iterables of\n length two). If keyword arguments are specified, the dictionary\n is then updated with those key/value pairs: ``d.update(red=1,\n blue=2)``.\n\n values()\n\n Return a new view of the dictionary\'s values. See below for\n documentation of view objects.\n\n\nDictionary view objects\n=======================\n\nThe objects returned by ``dict.keys()``, ``dict.values()`` and\n``dict.items()`` are *view objects*. They provide a dynamic view on\nthe dictionary\'s entries, which means that when the dictionary\nchanges, the view reflects these changes.\n\nDictionary views can be iterated over to yield their respective data,\nand support membership tests:\n\nlen(dictview)\n\n Return the number of entries in the dictionary.\n\niter(dictview)\n\n Return an iterator over the keys, values or items (represented as\n tuples of ``(key, value)``) in the dictionary.\n\n Keys and values are iterated over in an arbitrary order which is\n non-random, varies across Python implementations, and depends on\n the dictionary\'s history of insertions and deletions. If keys,\n values and items views are iterated over with no intervening\n modifications to the dictionary, the order of items will directly\n correspond. This allows the creation of ``(value, key)`` pairs\n using ``zip()``: ``pairs = zip(d.values(), d.keys())``. Another\n way to create the same list is ``pairs = [(v, k) for (k, v) in\n d.items()]``.\n\n Iterating views while adding or deleting entries in the dictionary\n may raise a ``RuntimeError`` or fail to iterate over all entries.\n\nx in dictview\n\n Return ``True`` if *x* is in the underlying dictionary\'s keys,\n values or items (in the latter case, *x* should be a ``(key,\n value)`` tuple).\n\nKeys views are set-like since their entries are unique and hashable.\nIf all values are hashable, so that ``(key, value)`` pairs are unique\nand hashable, then the items view is also set-like. (Values views are\nnot treated as set-like since the entries are generally not unique.)\nFor set-like views, all of the operations defined for the abstract\nbase class ``collections.Set`` are available (for example, ``==``,\n``<``, or ``^``).\n\nAn example of dictionary view usage:\n\n >>> dishes = {\'eggs\': 2, \'sausage\': 1, \'bacon\': 1, \'spam\': 500}\n >>> keys = dishes.keys()\n >>> values = dishes.values()\n\n >>> # iteration\n >>> n = 0\n >>> for val in values:\n ... n += val\n >>> print(n)\n 504\n\n >>> # keys and values are iterated over in the same order\n >>> list(keys)\n [\'eggs\', \'bacon\', \'sausage\', \'spam\']\n >>> list(values)\n [2, 1, 1, 500]\n\n >>> # view objects are dynamic and reflect dict changes\n >>> del dishes[\'eggs\']\n >>> del dishes[\'sausage\']\n >>> list(keys)\n [\'spam\', \'bacon\']\n\n >>> # set operations\n >>> keys & {\'eggs\', \'bacon\', \'salad\'}\n {\'bacon\'}\n >>> keys ^ {\'sausage\', \'juice\'}\n {\'juice\', \'eggs\', \'bacon\', \'spam\'}\n', 'typesmethods': "\nMethods\n*******\n\nMethods are functions that are called using the attribute notation.\nThere are two flavors: built-in methods (such as ``append()`` on\nlists) and class instance methods. Built-in methods are described\nwith the types that support them.\n\nIf you access a method (a function defined in a class namespace)\nthrough an instance, you get a special object: a *bound method* (also\ncalled *instance method*) object. When called, it will add the\n``self`` argument to the argument list. Bound methods have two\nspecial read-only attributes: ``m.__self__`` is the object on which\nthe method operates, and ``m.__func__`` is the function implementing\nthe method. Calling ``m(arg-1, arg-2, ..., arg-n)`` is completely\nequivalent to calling ``m.__func__(m.__self__, arg-1, arg-2, ...,\narg-n)``.\n\nLike function objects, bound method objects support getting arbitrary\nattributes. However, since method attributes are actually stored on\nthe underlying function object (``meth.__func__``), setting method\nattributes on bound methods is disallowed. Attempting to set a method\nattribute results in a ``TypeError`` being raised. In order to set a\nmethod attribute, you need to explicitly set it on the underlying\nfunction object:\n\n class C:\n def method(self):\n pass\n\n c = C()\n c.method.__func__.whoami = 'my name is c'\n\nSee *The standard type hierarchy* for more information.\n", 'typesmodules': "\nModules\n*******\n\nThe only special operation on a module is attribute access:\n``m.name``, where *m* is a module and *name* accesses a name defined\nin *m*'s symbol table. Module attributes can be assigned to. (Note\nthat the ``import`` statement is not, strictly speaking, an operation\non a module object; ``import foo`` does not require a module object\nnamed *foo* to exist, rather it requires an (external) *definition*\nfor a module named *foo* somewhere.)\n\nA special member of every module is ``__dict__``. This is the\ndictionary containing the module's symbol table. Modifying this\ndictionary will actually change the module's symbol table, but direct\nassignment to the ``__dict__`` attribute is not possible (you can\nwrite ``m.__dict__['a'] = 1``, which defines ``m.a`` to be ``1``, but\nyou can't write ``m.__dict__ = {}``). Modifying ``__dict__`` directly\nis not recommended.\n\nModules built into the interpreter are written like this: ````. If loaded from a file, they are written as\n````.\n", - 'typesseq': '\nSequence Types --- ``str``, ``bytes``, ``bytearray``, ``list``, ``tuple``, ``range``\n************************************************************************************\n\nThere are six sequence types: strings, byte sequences (``bytes``\nobjects), byte arrays (``bytearray`` objects), lists, tuples, and\nrange objects. For other containers see the built in ``dict`` and\n``set`` classes, and the ``collections`` module.\n\nStrings contain Unicode characters. Their literals are written in\nsingle or double quotes: ``\'xyzzy\'``, ``"frobozz"``. See *String and\nBytes literals* for more about string literals. In addition to the\nfunctionality described here, there are also string-specific methods\ndescribed in the *String Methods* section.\n\nBytes and bytearray objects contain single bytes -- the former is\nimmutable while the latter is a mutable sequence. Bytes objects can\nbe constructed the constructor, ``bytes()``, and from literals; use a\n``b`` prefix with normal string syntax: ``b\'xyzzy\'``. To construct\nbyte arrays, use the ``bytearray()`` function.\n\nWarning: While string objects are sequences of characters (represented by\n strings of length 1), bytes and bytearray objects are sequences of\n *integers* (between 0 and 255), representing the ASCII value of\n single bytes. That means that for a bytes or bytearray object *b*,\n ``b[0]`` will be an integer, while ``b[0:1]`` will be a bytes or\n bytearray object of length 1. The representation of bytes objects\n uses the literal format (``b\'...\'``) since it is generally more\n useful than e.g. ``bytes([50, 19, 100])``. You can always convert a\n bytes object into a list of integers using ``list(b)``.Also, while\n in previous Python versions, byte strings and Unicode strings could\n be exchanged for each other rather freely (barring encoding issues),\n strings and bytes are now completely separate concepts. There\'s no\n implicit en-/decoding if you pass and object of the wrong type. A\n string always compares unequal to a bytes or bytearray object.\n\nLists are constructed with square brackets, separating items with\ncommas: ``[a, b, c]``. Tuples are constructed by the comma operator\n(not within square brackets), with or without enclosing parentheses,\nbut an empty tuple must have the enclosing parentheses, such as ``a,\nb, c`` or ``()``. A single item tuple must have a trailing comma,\nsuch as ``(d,)``.\n\nObjects of type range are created using the ``range()`` function.\nThey don\'t support slicing, concatenation or repetition, and using\n``in``, ``not in``, ``min()`` or ``max()`` on them is inefficient.\n\nMost sequence types support the following operations. The ``in`` and\n``not in`` operations have the same priorities as the comparison\noperations. The ``+`` and ``*`` operations have the same priority as\nthe corresponding numeric operations. [3] Additional methods are\nprovided for *Mutable Sequence Types*.\n\nThis table lists the sequence operations sorted in ascending priority\n(operations in the same box have the same priority). In the table,\n*s* and *t* are sequences of the same type; *n*, *i* and *j* are\nintegers:\n\n+--------------------+----------------------------------+------------+\n| Operation | Result | Notes |\n+====================+==================================+============+\n| ``x in s`` | ``True`` if an item of *s* is | (1) |\n| | equal to *x*, else ``False`` | |\n+--------------------+----------------------------------+------------+\n| ``x not in s`` | ``False`` if an item of *s* is | (1) |\n| | equal to *x*, else ``True`` | |\n+--------------------+----------------------------------+------------+\n| ``s + t`` | the concatenation of *s* and *t* | (6) |\n+--------------------+----------------------------------+------------+\n| ``s * n, n * s`` | *n* shallow copies of *s* | (2) |\n| | concatenated | |\n+--------------------+----------------------------------+------------+\n| ``s[i]`` | *i*\'th item of *s*, origin 0 | (3) |\n+--------------------+----------------------------------+------------+\n| ``s[i:j]`` | slice of *s* from *i* to *j* | (3)(4) |\n+--------------------+----------------------------------+------------+\n| ``s[i:j:k]`` | slice of *s* from *i* to *j* | (3)(5) |\n| | with step *k* | |\n+--------------------+----------------------------------+------------+\n| ``len(s)`` | length of *s* | |\n+--------------------+----------------------------------+------------+\n| ``min(s)`` | smallest item of *s* | |\n+--------------------+----------------------------------+------------+\n| ``max(s)`` | largest item of *s* | |\n+--------------------+----------------------------------+------------+\n\nSequence types also support comparisons. In particular, tuples and\nlists are compared lexicographically by comparing corresponding\nelements. This means that to compare equal, every element must\ncompare equal and the two sequences must be of the same type and have\nthe same length. (For full details see *Comparisons* in the language\nreference.)\n\nNotes:\n\n1. When *s* is a string object, the ``in`` and ``not in`` operations\n act like a substring test.\n\n2. Values of *n* less than ``0`` are treated as ``0`` (which yields an\n empty sequence of the same type as *s*). Note also that the copies\n are shallow; nested structures are not copied. This often haunts\n new Python programmers; consider:\n\n >>> lists = [[]] * 3\n >>> lists\n [[], [], []]\n >>> lists[0].append(3)\n >>> lists\n [[3], [3], [3]]\n\n What has happened is that ``[[]]`` is a one-element list containing\n an empty list, so all three elements of ``[[]] * 3`` are (pointers\n to) this single empty list. Modifying any of the elements of\n ``lists`` modifies this single list. You can create a list of\n different lists this way:\n\n >>> lists = [[] for i in range(3)]\n >>> lists[0].append(3)\n >>> lists[1].append(5)\n >>> lists[2].append(7)\n >>> lists\n [[3], [5], [7]]\n\n3. If *i* or *j* is negative, the index is relative to the end of the\n string: ``len(s) + i`` or ``len(s) + j`` is substituted. But note\n that ``-0`` is still ``0``.\n\n4. The slice of *s* from *i* to *j* is defined as the sequence of\n items with index *k* such that ``i <= k < j``. If *i* or *j* is\n greater than ``len(s)``, use ``len(s)``. If *i* is omitted or\n ``None``, use ``0``. If *j* is omitted or ``None``, use\n ``len(s)``. If *i* is greater than or equal to *j*, the slice is\n empty.\n\n5. The slice of *s* from *i* to *j* with step *k* is defined as the\n sequence of items with index ``x = i + n*k`` such that ``0 <= n <\n (j-i)/k``. In other words, the indices are ``i``, ``i+k``,\n ``i+2*k``, ``i+3*k`` and so on, stopping when *j* is reached (but\n never including *j*). If *i* or *j* is greater than ``len(s)``,\n use ``len(s)``. If *i* or *j* are omitted or ``None``, they become\n "end" values (which end depends on the sign of *k*). Note, *k*\n cannot be zero. If *k* is ``None``, it is treated like ``1``.\n\n6. If *s* and *t* are both strings, some Python implementations such\n as CPython can usually perform an in-place optimization for\n assignments of the form ``s=s+t`` or ``s+=t``. When applicable,\n this optimization makes quadratic run-time much less likely. This\n optimization is both version and implementation dependent. For\n performance sensitive code, it is preferable to use the\n ``str.join()`` method which assures consistent linear concatenation\n performance across versions and implementations.\n\n\nString Methods\n==============\n\nString objects support the methods listed below. Note that none of\nthese methods take keyword arguments.\n\nIn addition, Python\'s strings support the sequence type methods\ndescribed in the *Sequence Types --- str, bytes, bytearray, list,\ntuple, range* section. To output formatted strings, see the *String\nFormatting* section. Also, see the ``re`` module for string functions\nbased on regular expressions.\n\nstr.capitalize()\n\n Return a copy of the string with only its first character\n capitalized.\n\nstr.center(width[, fillchar])\n\n Return centered in a string of length *width*. Padding is done\n using the specified *fillchar* (default is a space).\n\nstr.count(sub[, start[, end]])\n\n Return the number of non-overlapping occurrences of substring *sub*\n in the range [*start*, *end*]. Optional arguments *start* and\n *end* are interpreted as in slice notation.\n\nstr.encode([encoding[, errors]])\n\n Return an encoded version of the string as a bytes object. Default\n encoding is the current default string encoding. *errors* may be\n given to set a different error handling scheme. The default for\n *errors* is ``\'strict\'``, meaning that encoding errors raise a\n ``UnicodeError``. Other possible values are ``\'ignore\'``,\n ``\'replace\'``, ``\'xmlcharrefreplace\'``, ``\'backslashreplace\'`` and\n any other name registered via ``codecs.register_error()``, see\n section *Codec Base Classes*. For a list of possible encodings, see\n section *Standard Encodings*.\n\nstr.endswith(suffix[, start[, end]])\n\n Return ``True`` if the string ends with the specified *suffix*,\n otherwise return ``False``. *suffix* can also be a tuple of\n suffixes to look for. With optional *start*, test beginning at\n that position. With optional *end*, stop comparing at that\n position.\n\nstr.expandtabs([tabsize])\n\n Return a copy of the string where all tab characters are replaced\n by one or more spaces, depending on the current column and the\n given tab size. The column number is reset to zero after each\n newline occurring in the string. If *tabsize* is not given, a tab\n size of ``8`` characters is assumed. This doesn\'t understand other\n non-printing characters or escape sequences.\n\nstr.find(sub[, start[, end]])\n\n Return the lowest index in the string where substring *sub* is\n found, such that *sub* is contained in the range [*start*, *end*].\n Optional arguments *start* and *end* are interpreted as in slice\n notation. Return ``-1`` if *sub* is not found.\n\nstr.format(*args, **kwargs)\n\n Perform a string formatting operation. The *format_string*\n argument can contain literal text or replacement fields delimited\n by braces ``{}``. Each replacement field contains either the\n numeric index of a positional argument, or the name of a keyword\n argument. Returns a copy of *format_string* where each replacement\n field is replaced with the string value of the corresponding\n argument.\n\n >>> "The sum of 1 + 2 is {0}".format(1+2)\n \'The sum of 1 + 2 is 3\'\n\n See *Format String Syntax* for a description of the various\n formatting options that can be specified in format strings.\n\nstr.index(sub[, start[, end]])\n\n Like ``find()``, but raise ``ValueError`` when the substring is not\n found.\n\nstr.isalnum()\n\n Return true if all characters in the string are alphanumeric and\n there is at least one character, false otherwise.\n\nstr.isalpha()\n\n Return true if all characters in the string are alphabetic and\n there is at least one character, false otherwise.\n\nstr.isdecimal()\n\n Return true if all characters in the string are decimal characters\n and there is at least one character, false otherwise. Decimal\n characters include digit characters, and all characters that that\n can be used to form decimal-radix numbers, e.g. U+0660, ARABIC-\n INDIC DIGIT ZERO.\n\nstr.isdigit()\n\n Return true if all characters in the string are digits and there is\n at least one character, false otherwise.\n\nstr.isidentifier()\n\n Return true if the string is a valid identifier according to the\n language definition, section *Identifiers and keywords*.\n\nstr.islower()\n\n Return true if all cased characters in the string are lowercase and\n there is at least one cased character, false otherwise.\n\nstr.isnumeric()\n\n Return true if all characters in the string are numeric characters,\n and there is at least one character, false otherwise. Numeric\n characters include digit characters, and all characters that have\n the Unicode numeric value property, e.g. U+2155, VULGAR FRACTION\n ONE FIFTH.\n\nstr.isprintable()\n\n Return true if all characters in the string are printable or the\n string is empty, false otherwise. Nonprintable characters are\n those characters defined in the Unicode character database as\n "Other" or "Separator", excepting the ASCII space (0x20) which is\n considered printable. (Note that printable characters in this\n context are those which should not be escaped when ``repr()`` is\n invoked on a string. It has no bearing on the handling of strings\n written to ``sys.stdout`` or ``sys.stderr``.)\n\nstr.isspace()\n\n Return true if there are only whitespace characters in the string\n and there is at least one character, false otherwise.\n\nstr.istitle()\n\n Return true if the string is a titlecased string and there is at\n least one character, for example uppercase characters may only\n follow uncased characters and lowercase characters only cased ones.\n Return false otherwise.\n\nstr.isupper()\n\n Return true if all cased characters in the string are uppercase and\n there is at least one cased character, false otherwise.\n\nstr.join(seq)\n\n Return a string which is the concatenation of the strings in the\n sequence *seq*. A ``TypeError`` will be raised if there are any\n non-string values in *seq*, including ``bytes`` objects. The\n separator between elements is the string providing this method.\n\nstr.ljust(width[, fillchar])\n\n Return the string left justified in a string of length *width*.\n Padding is done using the specified *fillchar* (default is a\n space). The original string is returned if *width* is less than\n ``len(s)``.\n\nstr.lower()\n\n Return a copy of the string converted to lowercase.\n\nstr.lstrip([chars])\n\n Return a copy of the string with leading characters removed. The\n *chars* argument is a string specifying the set of characters to be\n removed. If omitted or ``None``, the *chars* argument defaults to\n removing whitespace. The *chars* argument is not a prefix; rather,\n all combinations of its values are stripped:\n\n >>> \' spacious \'.lstrip()\n \'spacious \'\n >>> \'www.example.com\'.lstrip(\'cmowz.\')\n \'example.com\'\n\nstatic str.maketrans(x[, y[, z]])\n\n This static method returns a translation table usable for\n ``str.translate()``.\n\n If there is only one argument, it must be a dictionary mapping\n Unicode ordinals (integers) or characters (strings of length 1) to\n Unicode ordinals, strings (of arbitrary lengths) or None.\n Character keys will then be converted to ordinals.\n\n If there are two arguments, they must be strings of equal length,\n and in the resulting dictionary, each character in x will be mapped\n to the character at the same position in y. If there is a third\n argument, it must be a string, whose characters will be mapped to\n None in the result.\n\nstr.partition(sep)\n\n Split the string at the first occurrence of *sep*, and return a\n 3-tuple containing the part before the separator, the separator\n itself, and the part after the separator. If the separator is not\n found, return a 3-tuple containing the string itself, followed by\n two empty strings.\n\nstr.replace(old, new[, count])\n\n Return a copy of the string with all occurrences of substring *old*\n replaced by *new*. If the optional argument *count* is given, only\n the first *count* occurrences are replaced.\n\nstr.rfind(sub[, start[, end]])\n\n Return the highest index in the string where substring *sub* is\n found, such that *sub* is contained within s[start,end]. Optional\n arguments *start* and *end* are interpreted as in slice notation.\n Return ``-1`` on failure.\n\nstr.rindex(sub[, start[, end]])\n\n Like ``rfind()`` but raises ``ValueError`` when the substring *sub*\n is not found.\n\nstr.rjust(width[, fillchar])\n\n Return the string right justified in a string of length *width*.\n Padding is done using the specified *fillchar* (default is a\n space). The original string is returned if *width* is less than\n ``len(s)``.\n\nstr.rpartition(sep)\n\n Split the string at the last occurrence of *sep*, and return a\n 3-tuple containing the part before the separator, the separator\n itself, and the part after the separator. If the separator is not\n found, return a 3-tuple containing two empty strings, followed by\n the string itself.\n\nstr.rsplit([sep[, maxsplit]])\n\n Return a list of the words in the string, using *sep* as the\n delimiter string. If *maxsplit* is given, at most *maxsplit* splits\n are done, the *rightmost* ones. If *sep* is not specified or\n ``None``, any whitespace string is a separator. Except for\n splitting from the right, ``rsplit()`` behaves like ``split()``\n which is described in detail below.\n\nstr.rstrip([chars])\n\n Return a copy of the string with trailing characters removed. The\n *chars* argument is a string specifying the set of characters to be\n removed. If omitted or ``None``, the *chars* argument defaults to\n removing whitespace. The *chars* argument is not a suffix; rather,\n all combinations of its values are stripped:\n\n >>> \' spacious \'.rstrip()\n \' spacious\'\n >>> \'mississippi\'.rstrip(\'ipz\')\n \'mississ\'\n\nstr.split([sep[, maxsplit]])\n\n Return a list of the words in the string, using *sep* as the\n delimiter string. If *maxsplit* is given, at most *maxsplit*\n splits are done (thus, the list will have at most ``maxsplit+1``\n elements). If *maxsplit* is not specified, then there is no limit\n on the number of splits (all possible splits are made).\n\n If *sep* is given, consecutive delimiters are not grouped together\n and are deemed to delimit empty strings (for example,\n ``\'1,,2\'.split(\',\')`` returns ``[\'1\', \'\', \'2\']``). The *sep*\n argument may consist of multiple characters (for example,\n ``\'1<>2<>3\'.split(\'<>\')`` returns ``[\'1\', \'2\', \'3\']``). Splitting\n an empty string with a specified separator returns ``[\'\']``.\n\n If *sep* is not specified or is ``None``, a different splitting\n algorithm is applied: runs of consecutive whitespace are regarded\n as a single separator, and the result will contain no empty strings\n at the start or end if the string has leading or trailing\n whitespace. Consequently, splitting an empty string or a string\n consisting of just whitespace with a ``None`` separator returns\n ``[]``.\n\n For example, ``\' 1 2 3 \'.split()`` returns ``[\'1\', \'2\', \'3\']``,\n and ``\' 1 2 3 \'.split(None, 1)`` returns ``[\'1\', \'2 3 \']``.\n\nstr.splitlines([keepends])\n\n Return a list of the lines in the string, breaking at line\n boundaries. Line breaks are not included in the resulting list\n unless *keepends* is given and true.\n\nstr.startswith(prefix[, start[, end]])\n\n Return ``True`` if string starts with the *prefix*, otherwise\n return ``False``. *prefix* can also be a tuple of prefixes to look\n for. With optional *start*, test string beginning at that\n position. With optional *end*, stop comparing string at that\n position.\n\nstr.strip([chars])\n\n Return a copy of the string with the leading and trailing\n characters removed. The *chars* argument is a string specifying the\n set of characters to be removed. If omitted or ``None``, the\n *chars* argument defaults to removing whitespace. The *chars*\n argument is not a prefix or suffix; rather, all combinations of its\n values are stripped:\n\n >>> \' spacious \'.strip()\n \'spacious\'\n >>> \'www.example.com\'.strip(\'cmowz.\')\n \'example\'\n\nstr.swapcase()\n\n Return a copy of the string with uppercase characters converted to\n lowercase and vice versa.\n\nstr.title()\n\n Return a titlecased version of the string: words start with\n uppercase characters, all remaining cased characters are lowercase.\n\nstr.translate(map)\n\n Return a copy of the *s* where all characters have been mapped\n through the *map* which must be a dictionary of Unicode ordinals\n (integers) to Unicode ordinals, strings or ``None``. Unmapped\n characters are left untouched. Characters mapped to ``None`` are\n deleted.\n\n You can use ``str.maketrans()`` to create a translation map from\n character-to-character mappings in different formats.\n\n Note: An even more flexible approach is to create a custom character\n mapping codec using the ``codecs`` module (see\n ``encodings.cp1251`` for an example).\n\nstr.upper()\n\n Return a copy of the string converted to uppercase.\n\nstr.zfill(width)\n\n Return the numeric string left filled with zeros in a string of\n length *width*. A sign prefix is handled correctly. The original\n string is returned if *width* is less than ``len(s)``.\n\n\nOld String Formatting Operations\n================================\n\nNote: The formatting operations described here are obsolete and may go\n away in future versions of Python. Use the new *String Formatting*\n in new code.\n\nString objects have one unique built-in operation: the ``%`` operator\n(modulo). This is also known as the string *formatting* or\n*interpolation* operator. Given ``format % values`` (where *format* is\na string), ``%`` conversion specifications in *format* are replaced\nwith zero or more elements of *values*. The effect is similar to the\nusing ``sprintf()`` in the C language.\n\nIf *format* requires a single argument, *values* may be a single non-\ntuple object. [4] Otherwise, *values* must be a tuple with exactly\nthe number of items specified by the format string, or a single\nmapping object (for example, a dictionary).\n\nA conversion specifier contains two or more characters and has the\nfollowing components, which must occur in this order:\n\n1. The ``\'%\'`` character, which marks the start of the specifier.\n\n2. Mapping key (optional), consisting of a parenthesised sequence of\n characters (for example, ``(somename)``).\n\n3. Conversion flags (optional), which affect the result of some\n conversion types.\n\n4. Minimum field width (optional). If specified as an ``\'*\'``\n (asterisk), the actual width is read from the next element of the\n tuple in *values*, and the object to convert comes after the\n minimum field width and optional precision.\n\n5. Precision (optional), given as a ``\'.\'`` (dot) followed by the\n precision. If specified as ``\'*\'`` (an asterisk), the actual width\n is read from the next element of the tuple in *values*, and the\n value to convert comes after the precision.\n\n6. Length modifier (optional).\n\n7. Conversion type.\n\nWhen the right argument is a dictionary (or other mapping type), then\nthe formats in the string *must* include a parenthesised mapping key\ninto that dictionary inserted immediately after the ``\'%\'`` character.\nThe mapping key selects the value to be formatted from the mapping.\nFor example:\n\n>>> print(\'%(language)s has %(#)03d quote types.\' % \\\n... {\'language\': "Python", "#": 2})\nPython has 002 quote types.\n\nIn this case no ``*`` specifiers may occur in a format (since they\nrequire a sequential parameter list).\n\nThe conversion flag characters are:\n\n+-----------+-----------------------------------------------------------------------+\n| Flag | Meaning |\n+===========+=======================================================================+\n| ``\'#\'`` | The value conversion will use the "alternate form" (where defined |\n| | below). |\n+-----------+-----------------------------------------------------------------------+\n| ``\'0\'`` | The conversion will be zero padded for numeric values. |\n+-----------+-----------------------------------------------------------------------+\n| ``\'-\'`` | The converted value is left adjusted (overrides the ``\'0\'`` |\n| | conversion if both are given). |\n+-----------+-----------------------------------------------------------------------+\n| ``\' \'`` | (a space) A blank should be left before a positive number (or empty |\n| | string) produced by a signed conversion. |\n+-----------+-----------------------------------------------------------------------+\n| ``\'+\'`` | A sign character (``\'+\'`` or ``\'-\'``) will precede the conversion |\n| | (overrides a "space" flag). |\n+-----------+-----------------------------------------------------------------------+\n\nA length modifier (``h``, ``l``, or ``L``) may be present, but is\nignored as it is not necessary for Python -- so e.g. ``%ld`` is\nidentical to ``%d``.\n\nThe conversion types are:\n\n+--------------+-------------------------------------------------------+---------+\n| Conversion | Meaning | Notes |\n+==============+=======================================================+=========+\n| ``\'d\'`` | Signed integer decimal. | |\n+--------------+-------------------------------------------------------+---------+\n| ``\'i\'`` | Signed integer decimal. | |\n+--------------+-------------------------------------------------------+---------+\n| ``\'o\'`` | Signed octal value. | (1) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'u\'`` | Obsolete type -- it is identical to ``\'d\'``. | (7) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'x\'`` | Signed hexadecimal (lowercase). | (2) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'X\'`` | Signed hexadecimal (uppercase). | (2) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'e\'`` | Floating point exponential format (lowercase). | (3) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'E\'`` | Floating point exponential format (uppercase). | (3) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'f\'`` | Floating point decimal format. | (3) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'F\'`` | Floating point decimal format. | (3) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'g\'`` | Floating point format. Uses lowercase exponential | (4) |\n| | format if exponent is less than -4 or not less than | |\n| | precision, decimal format otherwise. | |\n+--------------+-------------------------------------------------------+---------+\n| ``\'G\'`` | Floating point format. Uses uppercase exponential | (4) |\n| | format if exponent is less than -4 or not less than | |\n| | precision, decimal format otherwise. | |\n+--------------+-------------------------------------------------------+---------+\n| ``\'c\'`` | Single character (accepts integer or single character | |\n| | string). | |\n+--------------+-------------------------------------------------------+---------+\n| ``\'r\'`` | String (converts any python object using ``repr()``). | (5) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'s\'`` | String (converts any python object using ``str()``). | |\n+--------------+-------------------------------------------------------+---------+\n| ``\'%\'`` | No argument is converted, results in a ``\'%\'`` | |\n| | character in the result. | |\n+--------------+-------------------------------------------------------+---------+\n\nNotes:\n\n1. The alternate form causes a leading zero (``\'0\'``) to be inserted\n between left-hand padding and the formatting of the number if the\n leading character of the result is not already a zero.\n\n2. The alternate form causes a leading ``\'0x\'`` or ``\'0X\'`` (depending\n on whether the ``\'x\'`` or ``\'X\'`` format was used) to be inserted\n between left-hand padding and the formatting of the number if the\n leading character of the result is not already a zero.\n\n3. The alternate form causes the result to always contain a decimal\n point, even if no digits follow it.\n\n The precision determines the number of digits after the decimal\n point and defaults to 6.\n\n4. The alternate form causes the result to always contain a decimal\n point, and trailing zeroes are not removed as they would otherwise\n be.\n\n The precision determines the number of significant digits before\n and after the decimal point and defaults to 6.\n\n5. The precision determines the maximal number of characters used.\n\n1. See **PEP 237**.\n\nSince Python strings have an explicit length, ``%s`` conversions do\nnot assume that ``\'\\0\'`` is the end of the string.\n\nChanged in version 3.1: ``%f`` conversions for numbers whose absolute\nvalue is over 1e50 are no longer replaced by ``%g`` conversions.\n\nAdditional string operations are defined in standard modules\n``string`` and ``re``.\n\n\nRange Type\n==========\n\nThe ``range`` type is an immutable sequence which is commonly used for\nlooping. The advantage of the ``range`` type is that an ``range``\nobject will always take the same amount of memory, no matter the size\nof the range it represents. There are no consistent performance\nadvantages.\n\nRange objects have very little behavior: they only support indexing,\niteration, and the ``len()`` function.\n\n\nMutable Sequence Types\n======================\n\nList and bytearray objects support additional operations that allow\nin-place modification of the object. Other mutable sequence types\n(when added to the language) should also support these operations.\nStrings and tuples are immutable sequence types: such objects cannot\nbe modified once created. The following operations are defined on\nmutable sequence types (where *x* is an arbitrary object).\n\nNote that while lists allow their items to be of any type, bytearray\nobject "items" are all integers in the range 0 <= x < 256.\n\n+--------------------------------+----------------------------------+-----------------------+\n| Operation | Result | Notes |\n+================================+==================================+=======================+\n| ``s[i] = x`` | item *i* of *s* is replaced by | |\n| | *x* | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s[i:j] = t`` | slice of *s* from *i* to *j* is | |\n| | replaced by the contents of the | |\n| | iterable *t* | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``del s[i:j]`` | same as ``s[i:j] = []`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s[i:j:k] = t`` | the elements of ``s[i:j:k]`` are | (1) |\n| | replaced by those of *t* | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``del s[i:j:k]`` | removes the elements of | |\n| | ``s[i:j:k]`` from the list | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.append(x)`` | same as ``s[len(s):len(s)] = | |\n| | [x]`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.extend(x)`` | same as ``s[len(s):len(s)] = x`` | (2) |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.count(x)`` | return number of *i*\'s for which | |\n| | ``s[i] == x`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.index(x[, i[, j]])`` | return smallest *k* such that | (3) |\n| | ``s[k] == x`` and ``i <= k < j`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.insert(i, x)`` | same as ``s[i:i] = [x]`` | (4) |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.pop([i])`` | same as ``x = s[i]; del s[i]; | (5) |\n| | return x`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.remove(x)`` | same as ``del s[s.index(x)]`` | (3) |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.reverse()`` | reverses the items of *s* in | (6) |\n| | place | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.sort([key[, reverse]])`` | sort the items of *s* in place | (6), (7), (8) |\n+--------------------------------+----------------------------------+-----------------------+\n\nNotes:\n\n1. *t* must have the same length as the slice it is replacing.\n\n2. *x* can be any iterable object.\n\n3. Raises ``ValueError`` when *x* is not found in *s*. When a negative\n index is passed as the second or third parameter to the ``index()``\n method, the sequence length is added, as for slice indices. If it\n is still negative, it is truncated to zero, as for slice indices.\n\n4. When a negative index is passed as the first parameter to the\n ``insert()`` method, the sequence length is added, as for slice\n indices. If it is still negative, it is truncated to zero, as for\n slice indices.\n\n5. The optional argument *i* defaults to ``-1``, so that by default\n the last item is removed and returned.\n\n6. The ``sort()`` and ``reverse()`` methods modify the sequence in\n place for economy of space when sorting or reversing a large\n sequence. To remind you that they operate by side effect, they\n don\'t return the sorted or reversed sequence.\n\n7. The ``sort()`` method takes optional arguments for controlling the\n comparisons. Each must be specified as a keyword argument.\n\n *key* specifies a function of one argument that is used to extract\n a comparison key from each list element: ``key=str.lower``. The\n default value is ``None``.\n\n *reverse* is a boolean value. If set to ``True``, then the list\n elements are sorted as if each comparison were reversed.\n\n The ``sort()`` method is guaranteed to be stable. A sort is stable\n if it guarantees not to change the relative order of elements that\n compare equal --- this is helpful for sorting in multiple passes\n (for example, sort by department, then by salary grade).\n\n While a list is being sorted, the effect of attempting to mutate,\n or even inspect, the list is undefined. The C implementation makes\n the list appear empty for the duration, and raises ``ValueError``\n if it can detect that the list has been mutated during a sort.\n\n8. ``sort()`` is not supported by ``bytearray`` objects.\n\n\nBytes and Byte Array Methods\n============================\n\nBytes and bytearray objects, being "strings of bytes", have all\nmethods found on strings, with the exception of ``encode()``,\n``format()`` and ``isidentifier()``, which do not make sense with\nthese types. For converting the objects to strings, they have a\n``decode()`` method.\n\nWherever one of these methods needs to interpret the bytes as\ncharacters (e.g. the ``is...()`` methods), the ASCII character set is\nassumed.\n\nNote: The methods on bytes and bytearray objects don\'t accept strings as\n their arguments, just as the methods on strings don\'t accept bytes\n as their arguments. For example, you have to write\n\n a = "abc"\n b = a.replace("a", "f")\n\n and\n\n a = b"abc"\n b = a.replace(b"a", b"f")\n\nbytes.decode([encoding[, errors]])\nbytearray.decode([encoding[, errors]])\n\n Return a string decoded from the given bytes. Default encoding is\n the current default string encoding. *errors* may be given to set\n a different error handling scheme. The default for *errors* is\n ``\'strict\'``, meaning that encoding errors raise a\n ``UnicodeError``. Other possible values are ``\'ignore\'``,\n ``\'replace\'`` and any other name registered via\n ``codecs.register_error()``, see section *Codec Base Classes*. For\n a list of possible encodings, see section *Standard Encodings*.\n\nThe bytes and bytearray types have an additional class method:\n\nclassmethod bytes.fromhex(string)\nclassmethod bytearray.fromhex(string)\n\n This ``bytes`` class method returns a bytes or bytearray object,\n decoding the given string object. The string must contain two\n hexadecimal digits per byte, spaces are ignored.\n\n >>> bytes.fromhex(\'f0 f1f2 \')\n b\'\\xf0\\xf1\\xf2\'\n\nThe maketrans and translate methods differ in semantics from the\nversions available on strings:\n\nbytes.translate(table[, delete])\nbytearray.translate(table[, delete])\n\n Return a copy of the bytes or bytearray object where all bytes\n occurring in the optional argument *delete* are removed, and the\n remaining bytes have been mapped through the given translation\n table, which must be a bytes object of length 256.\n\n You can use the ``bytes.maketrans()`` method to create a\n translation table.\n\n Set the *table* argument to ``None`` for translations that only\n delete characters:\n\n >>> b\'read this short text\'.translate(None, b\'aeiou\')\n b\'rd ths shrt txt\'\n\nstatic bytes.maketrans(from, to)\nstatic bytearray.maketrans(from, to)\n\n This static method returns a translation table usable for\n ``bytes.translate()`` that will map each character in *from* into\n the character at the same position in *to*; *from* and *to* must be\n bytes objects and have the same length.\n\n New in version 3.1.\n', - 'typesseq-mutable': '\nMutable Sequence Types\n**********************\n\nList and bytearray objects support additional operations that allow\nin-place modification of the object. Other mutable sequence types\n(when added to the language) should also support these operations.\nStrings and tuples are immutable sequence types: such objects cannot\nbe modified once created. The following operations are defined on\nmutable sequence types (where *x* is an arbitrary object).\n\nNote that while lists allow their items to be of any type, bytearray\nobject "items" are all integers in the range 0 <= x < 256.\n\n+--------------------------------+----------------------------------+-----------------------+\n| Operation | Result | Notes |\n+================================+==================================+=======================+\n| ``s[i] = x`` | item *i* of *s* is replaced by | |\n| | *x* | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s[i:j] = t`` | slice of *s* from *i* to *j* is | |\n| | replaced by the contents of the | |\n| | iterable *t* | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``del s[i:j]`` | same as ``s[i:j] = []`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s[i:j:k] = t`` | the elements of ``s[i:j:k]`` are | (1) |\n| | replaced by those of *t* | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``del s[i:j:k]`` | removes the elements of | |\n| | ``s[i:j:k]`` from the list | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.append(x)`` | same as ``s[len(s):len(s)] = | |\n| | [x]`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.extend(x)`` | same as ``s[len(s):len(s)] = x`` | (2) |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.count(x)`` | return number of *i*\'s for which | |\n| | ``s[i] == x`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.index(x[, i[, j]])`` | return smallest *k* such that | (3) |\n| | ``s[k] == x`` and ``i <= k < j`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.insert(i, x)`` | same as ``s[i:i] = [x]`` | (4) |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.pop([i])`` | same as ``x = s[i]; del s[i]; | (5) |\n| | return x`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.remove(x)`` | same as ``del s[s.index(x)]`` | (3) |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.reverse()`` | reverses the items of *s* in | (6) |\n| | place | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.sort([key[, reverse]])`` | sort the items of *s* in place | (6), (7), (8) |\n+--------------------------------+----------------------------------+-----------------------+\n\nNotes:\n\n1. *t* must have the same length as the slice it is replacing.\n\n2. *x* can be any iterable object.\n\n3. Raises ``ValueError`` when *x* is not found in *s*. When a negative\n index is passed as the second or third parameter to the ``index()``\n method, the sequence length is added, as for slice indices. If it\n is still negative, it is truncated to zero, as for slice indices.\n\n4. When a negative index is passed as the first parameter to the\n ``insert()`` method, the sequence length is added, as for slice\n indices. If it is still negative, it is truncated to zero, as for\n slice indices.\n\n5. The optional argument *i* defaults to ``-1``, so that by default\n the last item is removed and returned.\n\n6. The ``sort()`` and ``reverse()`` methods modify the sequence in\n place for economy of space when sorting or reversing a large\n sequence. To remind you that they operate by side effect, they\n don\'t return the sorted or reversed sequence.\n\n7. The ``sort()`` method takes optional arguments for controlling the\n comparisons. Each must be specified as a keyword argument.\n\n *key* specifies a function of one argument that is used to extract\n a comparison key from each list element: ``key=str.lower``. The\n default value is ``None``.\n\n *reverse* is a boolean value. If set to ``True``, then the list\n elements are sorted as if each comparison were reversed.\n\n The ``sort()`` method is guaranteed to be stable. A sort is stable\n if it guarantees not to change the relative order of elements that\n compare equal --- this is helpful for sorting in multiple passes\n (for example, sort by department, then by salary grade).\n\n While a list is being sorted, the effect of attempting to mutate,\n or even inspect, the list is undefined. The C implementation makes\n the list appear empty for the duration, and raises ``ValueError``\n if it can detect that the list has been mutated during a sort.\n\n8. ``sort()`` is not supported by ``bytearray`` objects.\n', + 'typesseq': '\nSequence Types --- ``str``, ``bytes``, ``bytearray``, ``list``, ``tuple``, ``range``\n************************************************************************************\n\nThere are six sequence types: strings, byte sequences (``bytes``\nobjects), byte arrays (``bytearray`` objects), lists, tuples, and\nrange objects. For other containers see the built in ``dict`` and\n``set`` classes, and the ``collections`` module.\n\nStrings contain Unicode characters. Their literals are written in\nsingle or double quotes: ``\'xyzzy\'``, ``"frobozz"``. See *String and\nBytes literals* for more about string literals. In addition to the\nfunctionality described here, there are also string-specific methods\ndescribed in the *String Methods* section.\n\nBytes and bytearray objects contain single bytes -- the former is\nimmutable while the latter is a mutable sequence. Bytes objects can\nbe constructed the constructor, ``bytes()``, and from literals; use a\n``b`` prefix with normal string syntax: ``b\'xyzzy\'``. To construct\nbyte arrays, use the ``bytearray()`` function.\n\nWarning: While string objects are sequences of characters (represented by\n strings of length 1), bytes and bytearray objects are sequences of\n *integers* (between 0 and 255), representing the ASCII value of\n single bytes. That means that for a bytes or bytearray object *b*,\n ``b[0]`` will be an integer, while ``b[0:1]`` will be a bytes or\n bytearray object of length 1. The representation of bytes objects\n uses the literal format (``b\'...\'``) since it is generally more\n useful than e.g. ``bytes([50, 19, 100])``. You can always convert a\n bytes object into a list of integers using ``list(b)``.Also, while\n in previous Python versions, byte strings and Unicode strings could\n be exchanged for each other rather freely (barring encoding issues),\n strings and bytes are now completely separate concepts. There\'s no\n implicit en-/decoding if you pass an object of the wrong type. A\n string always compares unequal to a bytes or bytearray object.\n\nLists are constructed with square brackets, separating items with\ncommas: ``[a, b, c]``. Tuples are constructed by the comma operator\n(not within square brackets), with or without enclosing parentheses,\nbut an empty tuple must have the enclosing parentheses, such as ``a,\nb, c`` or ``()``. A single item tuple must have a trailing comma,\nsuch as ``(d,)``.\n\nObjects of type range are created using the ``range()`` function.\nThey don\'t support slicing, concatenation or repetition, and using\n``in``, ``not in``, ``min()`` or ``max()`` on them is inefficient.\n\nMost sequence types support the following operations. The ``in`` and\n``not in`` operations have the same priorities as the comparison\noperations. The ``+`` and ``*`` operations have the same priority as\nthe corresponding numeric operations. [3] Additional methods are\nprovided for *Mutable Sequence Types*.\n\nThis table lists the sequence operations sorted in ascending priority\n(operations in the same box have the same priority). In the table,\n*s* and *t* are sequences of the same type; *n*, *i* and *j* are\nintegers:\n\n+--------------------+----------------------------------+------------+\n| Operation | Result | Notes |\n+====================+==================================+============+\n| ``x in s`` | ``True`` if an item of *s* is | (1) |\n| | equal to *x*, else ``False`` | |\n+--------------------+----------------------------------+------------+\n| ``x not in s`` | ``False`` if an item of *s* is | (1) |\n| | equal to *x*, else ``True`` | |\n+--------------------+----------------------------------+------------+\n| ``s + t`` | the concatenation of *s* and *t* | (6) |\n+--------------------+----------------------------------+------------+\n| ``s * n, n * s`` | *n* shallow copies of *s* | (2) |\n| | concatenated | |\n+--------------------+----------------------------------+------------+\n| ``s[i]`` | *i*\'th item of *s*, origin 0 | (3) |\n+--------------------+----------------------------------+------------+\n| ``s[i:j]`` | slice of *s* from *i* to *j* | (3)(4) |\n+--------------------+----------------------------------+------------+\n| ``s[i:j:k]`` | slice of *s* from *i* to *j* | (3)(5) |\n| | with step *k* | |\n+--------------------+----------------------------------+------------+\n| ``len(s)`` | length of *s* | |\n+--------------------+----------------------------------+------------+\n| ``min(s)`` | smallest item of *s* | |\n+--------------------+----------------------------------+------------+\n| ``max(s)`` | largest item of *s* | |\n+--------------------+----------------------------------+------------+\n| ``s.index(i)`` | index of the first occurence of | |\n| | *i* in *s* | |\n+--------------------+----------------------------------+------------+\n| ``s.count(i)`` | total number of occurences of | |\n| | *i* in *s* | |\n+--------------------+----------------------------------+------------+\n\nSequence types also support comparisons. In particular, tuples and\nlists are compared lexicographically by comparing corresponding\nelements. This means that to compare equal, every element must\ncompare equal and the two sequences must be of the same type and have\nthe same length. (For full details see *Comparisons* in the language\nreference.)\n\nNotes:\n\n1. When *s* is a string object, the ``in`` and ``not in`` operations\n act like a substring test.\n\n2. Values of *n* less than ``0`` are treated as ``0`` (which yields an\n empty sequence of the same type as *s*). Note also that the copies\n are shallow; nested structures are not copied. This often haunts\n new Python programmers; consider:\n\n >>> lists = [[]] * 3\n >>> lists\n [[], [], []]\n >>> lists[0].append(3)\n >>> lists\n [[3], [3], [3]]\n\n What has happened is that ``[[]]`` is a one-element list containing\n an empty list, so all three elements of ``[[]] * 3`` are (pointers\n to) this single empty list. Modifying any of the elements of\n ``lists`` modifies this single list. You can create a list of\n different lists this way:\n\n >>> lists = [[] for i in range(3)]\n >>> lists[0].append(3)\n >>> lists[1].append(5)\n >>> lists[2].append(7)\n >>> lists\n [[3], [5], [7]]\n\n3. If *i* or *j* is negative, the index is relative to the end of the\n string: ``len(s) + i`` or ``len(s) + j`` is substituted. But note\n that ``-0`` is still ``0``.\n\n4. The slice of *s* from *i* to *j* is defined as the sequence of\n items with index *k* such that ``i <= k < j``. If *i* or *j* is\n greater than ``len(s)``, use ``len(s)``. If *i* is omitted or\n ``None``, use ``0``. If *j* is omitted or ``None``, use\n ``len(s)``. If *i* is greater than or equal to *j*, the slice is\n empty.\n\n5. The slice of *s* from *i* to *j* with step *k* is defined as the\n sequence of items with index ``x = i + n*k`` such that ``0 <= n <\n (j-i)/k``. In other words, the indices are ``i``, ``i+k``,\n ``i+2*k``, ``i+3*k`` and so on, stopping when *j* is reached (but\n never including *j*). If *i* or *j* is greater than ``len(s)``,\n use ``len(s)``. If *i* or *j* are omitted or ``None``, they become\n "end" values (which end depends on the sign of *k*). Note, *k*\n cannot be zero. If *k* is ``None``, it is treated like ``1``.\n\n6. **CPython implementation detail:** If *s* and *t* are both strings,\n some Python implementations such as CPython can usually perform an\n in-place optimization for assignments of the form ``s = s + t`` or\n ``s += t``. When applicable, this optimization makes quadratic\n run-time much less likely. This optimization is both version and\n implementation dependent. For performance sensitive code, it is\n preferable to use the ``str.join()`` method which assures\n consistent linear concatenation performance across versions and\n implementations.\n\n\nString Methods\n==============\n\nString objects support the methods listed below. Note that none of\nthese methods take keyword arguments.\n\nIn addition, Python\'s strings support the sequence type methods\ndescribed in the *Sequence Types --- str, bytes, bytearray, list,\ntuple, range* section. To output formatted strings, see the *String\nFormatting* section. Also, see the ``re`` module for string functions\nbased on regular expressions.\n\nstr.capitalize()\n\n Return a copy of the string with its first character capitalized\n and the rest lowercased.\n\nstr.center(width[, fillchar])\n\n Return centered in a string of length *width*. Padding is done\n using the specified *fillchar* (default is a space).\n\nstr.count(sub[, start[, end]])\n\n Return the number of non-overlapping occurrences of substring *sub*\n in the range [*start*, *end*]. Optional arguments *start* and\n *end* are interpreted as in slice notation.\n\nstr.encode([encoding[, errors]])\n\n Return an encoded version of the string as a bytes object. Default\n encoding is the current default string encoding. *errors* may be\n given to set a different error handling scheme. The default for\n *errors* is ``\'strict\'``, meaning that encoding errors raise a\n ``UnicodeError``. Other possible values are ``\'ignore\'``,\n ``\'replace\'``, ``\'xmlcharrefreplace\'``, ``\'backslashreplace\'`` and\n any other name registered via ``codecs.register_error()``, see\n section *Codec Base Classes*. For a list of possible encodings, see\n section *Standard Encodings*.\n\n Changed in version 3.1: Support for keyword arguments added.\n\nstr.endswith(suffix[, start[, end]])\n\n Return ``True`` if the string ends with the specified *suffix*,\n otherwise return ``False``. *suffix* can also be a tuple of\n suffixes to look for. With optional *start*, test beginning at\n that position. With optional *end*, stop comparing at that\n position.\n\nstr.expandtabs([tabsize])\n\n Return a copy of the string where all tab characters are replaced\n by one or more spaces, depending on the current column and the\n given tab size. The column number is reset to zero after each\n newline occurring in the string. If *tabsize* is not given, a tab\n size of ``8`` characters is assumed. This doesn\'t understand other\n non-printing characters or escape sequences.\n\nstr.find(sub[, start[, end]])\n\n Return the lowest index in the string where substring *sub* is\n found, such that *sub* is contained in the slice ``s[start:end]``.\n Optional arguments *start* and *end* are interpreted as in slice\n notation. Return ``-1`` if *sub* is not found.\n\nstr.format(*args, **kwargs)\n\n Perform a string formatting operation. The *format_string*\n argument can contain literal text or replacement fields delimited\n by braces ``{}``. Each replacement field contains either the\n numeric index of a positional argument, or the name of a keyword\n argument. Returns a copy of *format_string* where each replacement\n field is replaced with the string value of the corresponding\n argument.\n\n >>> "The sum of 1 + 2 is {0}".format(1+2)\n \'The sum of 1 + 2 is 3\'\n\n See *Format String Syntax* for a description of the various\n formatting options that can be specified in format strings.\n\nstr.index(sub[, start[, end]])\n\n Like ``find()``, but raise ``ValueError`` when the substring is not\n found.\n\nstr.isalnum()\n\n Return true if all characters in the string are alphanumeric and\n there is at least one character, false otherwise. A character\n ``c`` is alphanumeric if one of the following returns ``True``:\n ``c.isalpha()``, ``c.isdecimal()``, ``c.isdigit()``, or\n ``c.isnumeric()``.\n\nstr.isalpha()\n\n Return true if all characters in the string are alphabetic and\n there is at least one character, false otherwise. Alphabetic\n characters are those characters defined in the Unicode character\n database as "Letter", i.e., those with general category property\n being one of "Lm", "Lt", "Lu", "Ll", or "Lo". Note that this is\n different from the "Alphabetic" property defined in the Unicode\n Standard.\n\nstr.isdecimal()\n\n Return true if all characters in the string are decimal characters\n and there is at least one character, false otherwise. Decimal\n characters are those from general category "Nd". This category\n includes digit characters, and all characters that that can be used\n to form decimal-radix numbers, e.g. U+0660, ARABIC-INDIC DIGIT\n ZERO.\n\nstr.isdigit()\n\n Return true if all characters in the string are digits and there is\n at least one character, false otherwise. Digits include decimal\n characters and digits that need special handling, such as the\n compatibility superscript digits. Formally, a digit is a character\n that has the property value Numeric_Type=Digit or\n Numeric_Type=Decimal.\n\nstr.isidentifier()\n\n Return true if the string is a valid identifier according to the\n language definition, section *Identifiers and keywords*.\n\nstr.islower()\n\n Return true if all cased characters in the string are lowercase and\n there is at least one cased character, false otherwise. Cased\n characters are those with general category property being one of\n "Lu", "Ll", or "Lt" and lowercase characters are those with general\n category property "Ll".\n\nstr.isnumeric()\n\n Return true if all characters in the string are numeric characters,\n and there is at least one character, false otherwise. Numeric\n characters include digit characters, and all characters that have\n the Unicode numeric value property, e.g. U+2155, VULGAR FRACTION\n ONE FIFTH. Formally, numeric characters are those with the\n property value Numeric_Type=Digit, Numeric_Type=Decimal or\n Numeric_Type=Numeric.\n\nstr.isprintable()\n\n Return true if all characters in the string are printable or the\n string is empty, false otherwise. Nonprintable characters are\n those characters defined in the Unicode character database as\n "Other" or "Separator", excepting the ASCII space (0x20) which is\n considered printable. (Note that printable characters in this\n context are those which should not be escaped when ``repr()`` is\n invoked on a string. It has no bearing on the handling of strings\n written to ``sys.stdout`` or ``sys.stderr``.)\n\nstr.isspace()\n\n Return true if there are only whitespace characters in the string\n and there is at least one character, false otherwise. Whitespace\n characters are those characters defined in the Unicode character\n database as "Other" or "Separator" and those with bidirectional\n property being one of "WS", "B", or "S".\n\nstr.istitle()\n\n Return true if the string is a titlecased string and there is at\n least one character, for example uppercase characters may only\n follow uncased characters and lowercase characters only cased ones.\n Return false otherwise.\n\nstr.isupper()\n\n Return true if all cased characters in the string are uppercase and\n there is at least one cased character, false otherwise. Cased\n characters are those with general category property being one of\n "Lu", "Ll", or "Lt" and uppercase characters are those with general\n category property "Lu".\n\nstr.join(iterable)\n\n Return a string which is the concatenation of the strings in the\n *iterable* *iterable*. A ``TypeError`` will be raised if there are\n any non-string values in *seq*, including ``bytes`` objects. The\n separator between elements is the string providing this method.\n\nstr.ljust(width[, fillchar])\n\n Return the string left justified in a string of length *width*.\n Padding is done using the specified *fillchar* (default is a\n space). The original string is returned if *width* is less than\n ``len(s)``.\n\nstr.lower()\n\n Return a copy of the string converted to lowercase.\n\nstr.lstrip([chars])\n\n Return a copy of the string with leading characters removed. The\n *chars* argument is a string specifying the set of characters to be\n removed. If omitted or ``None``, the *chars* argument defaults to\n removing whitespace. The *chars* argument is not a prefix; rather,\n all combinations of its values are stripped:\n\n >>> \' spacious \'.lstrip()\n \'spacious \'\n >>> \'www.example.com\'.lstrip(\'cmowz.\')\n \'example.com\'\n\nstatic str.maketrans(x[, y[, z]])\n\n This static method returns a translation table usable for\n ``str.translate()``.\n\n If there is only one argument, it must be a dictionary mapping\n Unicode ordinals (integers) or characters (strings of length 1) to\n Unicode ordinals, strings (of arbitrary lengths) or None.\n Character keys will then be converted to ordinals.\n\n If there are two arguments, they must be strings of equal length,\n and in the resulting dictionary, each character in x will be mapped\n to the character at the same position in y. If there is a third\n argument, it must be a string, whose characters will be mapped to\n None in the result.\n\nstr.partition(sep)\n\n Split the string at the first occurrence of *sep*, and return a\n 3-tuple containing the part before the separator, the separator\n itself, and the part after the separator. If the separator is not\n found, return a 3-tuple containing the string itself, followed by\n two empty strings.\n\nstr.replace(old, new[, count])\n\n Return a copy of the string with all occurrences of substring *old*\n replaced by *new*. If the optional argument *count* is given, only\n the first *count* occurrences are replaced.\n\nstr.rfind(sub[, start[, end]])\n\n Return the highest index in the string where substring *sub* is\n found, such that *sub* is contained within ``s[start:end]``.\n Optional arguments *start* and *end* are interpreted as in slice\n notation. Return ``-1`` on failure.\n\nstr.rindex(sub[, start[, end]])\n\n Like ``rfind()`` but raises ``ValueError`` when the substring *sub*\n is not found.\n\nstr.rjust(width[, fillchar])\n\n Return the string right justified in a string of length *width*.\n Padding is done using the specified *fillchar* (default is a\n space). The original string is returned if *width* is less than\n ``len(s)``.\n\nstr.rpartition(sep)\n\n Split the string at the last occurrence of *sep*, and return a\n 3-tuple containing the part before the separator, the separator\n itself, and the part after the separator. If the separator is not\n found, return a 3-tuple containing two empty strings, followed by\n the string itself.\n\nstr.rsplit([sep[, maxsplit]])\n\n Return a list of the words in the string, using *sep* as the\n delimiter string. If *maxsplit* is given, at most *maxsplit* splits\n are done, the *rightmost* ones. If *sep* is not specified or\n ``None``, any whitespace string is a separator. Except for\n splitting from the right, ``rsplit()`` behaves like ``split()``\n which is described in detail below.\n\nstr.rstrip([chars])\n\n Return a copy of the string with trailing characters removed. The\n *chars* argument is a string specifying the set of characters to be\n removed. If omitted or ``None``, the *chars* argument defaults to\n removing whitespace. The *chars* argument is not a suffix; rather,\n all combinations of its values are stripped:\n\n >>> \' spacious \'.rstrip()\n \' spacious\'\n >>> \'mississippi\'.rstrip(\'ipz\')\n \'mississ\'\n\nstr.split([sep[, maxsplit]])\n\n Return a list of the words in the string, using *sep* as the\n delimiter string. If *maxsplit* is given, at most *maxsplit*\n splits are done (thus, the list will have at most ``maxsplit+1``\n elements). If *maxsplit* is not specified, then there is no limit\n on the number of splits (all possible splits are made).\n\n If *sep* is given, consecutive delimiters are not grouped together\n and are deemed to delimit empty strings (for example,\n ``\'1,,2\'.split(\',\')`` returns ``[\'1\', \'\', \'2\']``). The *sep*\n argument may consist of multiple characters (for example,\n ``\'1<>2<>3\'.split(\'<>\')`` returns ``[\'1\', \'2\', \'3\']``). Splitting\n an empty string with a specified separator returns ``[\'\']``.\n\n If *sep* is not specified or is ``None``, a different splitting\n algorithm is applied: runs of consecutive whitespace are regarded\n as a single separator, and the result will contain no empty strings\n at the start or end if the string has leading or trailing\n whitespace. Consequently, splitting an empty string or a string\n consisting of just whitespace with a ``None`` separator returns\n ``[]``.\n\n For example, ``\' 1 2 3 \'.split()`` returns ``[\'1\', \'2\', \'3\']``,\n and ``\' 1 2 3 \'.split(None, 1)`` returns ``[\'1\', \'2 3 \']``.\n\nstr.splitlines([keepends])\n\n Return a list of the lines in the string, breaking at line\n boundaries. Line breaks are not included in the resulting list\n unless *keepends* is given and true.\n\nstr.startswith(prefix[, start[, end]])\n\n Return ``True`` if string starts with the *prefix*, otherwise\n return ``False``. *prefix* can also be a tuple of prefixes to look\n for. With optional *start*, test string beginning at that\n position. With optional *end*, stop comparing string at that\n position.\n\nstr.strip([chars])\n\n Return a copy of the string with the leading and trailing\n characters removed. The *chars* argument is a string specifying the\n set of characters to be removed. If omitted or ``None``, the\n *chars* argument defaults to removing whitespace. The *chars*\n argument is not a prefix or suffix; rather, all combinations of its\n values are stripped:\n\n >>> \' spacious \'.strip()\n \'spacious\'\n >>> \'www.example.com\'.strip(\'cmowz.\')\n \'example\'\n\nstr.swapcase()\n\n Return a copy of the string with uppercase characters converted to\n lowercase and vice versa.\n\nstr.title()\n\n Return a titlecased version of the string where words start with an\n uppercase character and the remaining characters are lowercase.\n\n The algorithm uses a simple language-independent definition of a\n word as groups of consecutive letters. The definition works in\n many contexts but it means that apostrophes in contractions and\n possessives form word boundaries, which may not be the desired\n result:\n\n >>> "they\'re bill\'s friends from the UK".title()\n "They\'Re Bill\'S Friends From The Uk"\n\n A workaround for apostrophes can be constructed using regular\n expressions:\n\n >>> import re\n >>> def titlecase(s):\n return re.sub(r"[A-Za-z]+(\'[A-Za-z]+)?",\n lambda mo: mo.group(0)[0].upper() +\n mo.group(0)[1:].lower(),\n s)\n\n >>> titlecase("they\'re bill\'s friends.")\n "They\'re Bill\'s Friends."\n\nstr.translate(map)\n\n Return a copy of the *s* where all characters have been mapped\n through the *map* which must be a dictionary of Unicode ordinals\n (integers) to Unicode ordinals, strings or ``None``. Unmapped\n characters are left untouched. Characters mapped to ``None`` are\n deleted.\n\n You can use ``str.maketrans()`` to create a translation map from\n character-to-character mappings in different formats.\n\n Note: An even more flexible approach is to create a custom character\n mapping codec using the ``codecs`` module (see\n ``encodings.cp1251`` for an example).\n\nstr.upper()\n\n Return a copy of the string converted to uppercase.\n\nstr.zfill(width)\n\n Return the numeric string left filled with zeros in a string of\n length *width*. A sign prefix is handled correctly. The original\n string is returned if *width* is less than ``len(s)``.\n\n\nOld String Formatting Operations\n================================\n\nNote: The formatting operations described here are obsolete and may go\n away in future versions of Python. Use the new *String Formatting*\n in new code.\n\nString objects have one unique built-in operation: the ``%`` operator\n(modulo). This is also known as the string *formatting* or\n*interpolation* operator. Given ``format % values`` (where *format* is\na string), ``%`` conversion specifications in *format* are replaced\nwith zero or more elements of *values*. The effect is similar to the\nusing ``sprintf()`` in the C language.\n\nIf *format* requires a single argument, *values* may be a single non-\ntuple object. [4] Otherwise, *values* must be a tuple with exactly\nthe number of items specified by the format string, or a single\nmapping object (for example, a dictionary).\n\nA conversion specifier contains two or more characters and has the\nfollowing components, which must occur in this order:\n\n1. The ``\'%\'`` character, which marks the start of the specifier.\n\n2. Mapping key (optional), consisting of a parenthesised sequence of\n characters (for example, ``(somename)``).\n\n3. Conversion flags (optional), which affect the result of some\n conversion types.\n\n4. Minimum field width (optional). If specified as an ``\'*\'``\n (asterisk), the actual width is read from the next element of the\n tuple in *values*, and the object to convert comes after the\n minimum field width and optional precision.\n\n5. Precision (optional), given as a ``\'.\'`` (dot) followed by the\n precision. If specified as ``\'*\'`` (an asterisk), the actual width\n is read from the next element of the tuple in *values*, and the\n value to convert comes after the precision.\n\n6. Length modifier (optional).\n\n7. Conversion type.\n\nWhen the right argument is a dictionary (or other mapping type), then\nthe formats in the string *must* include a parenthesised mapping key\ninto that dictionary inserted immediately after the ``\'%\'`` character.\nThe mapping key selects the value to be formatted from the mapping.\nFor example:\n\n>>> print(\'%(language)s has %(number)03d quote types.\' %\n... {\'language\': "Python", "number": 2})\nPython has 002 quote types.\n\nIn this case no ``*`` specifiers may occur in a format (since they\nrequire a sequential parameter list).\n\nThe conversion flag characters are:\n\n+-----------+-----------------------------------------------------------------------+\n| Flag | Meaning |\n+===========+=======================================================================+\n| ``\'#\'`` | The value conversion will use the "alternate form" (where defined |\n| | below). |\n+-----------+-----------------------------------------------------------------------+\n| ``\'0\'`` | The conversion will be zero padded for numeric values. |\n+-----------+-----------------------------------------------------------------------+\n| ``\'-\'`` | The converted value is left adjusted (overrides the ``\'0\'`` |\n| | conversion if both are given). |\n+-----------+-----------------------------------------------------------------------+\n| ``\' \'`` | (a space) A blank should be left before a positive number (or empty |\n| | string) produced by a signed conversion. |\n+-----------+-----------------------------------------------------------------------+\n| ``\'+\'`` | A sign character (``\'+\'`` or ``\'-\'``) will precede the conversion |\n| | (overrides a "space" flag). |\n+-----------+-----------------------------------------------------------------------+\n\nA length modifier (``h``, ``l``, or ``L``) may be present, but is\nignored as it is not necessary for Python -- so e.g. ``%ld`` is\nidentical to ``%d``.\n\nThe conversion types are:\n\n+--------------+-------------------------------------------------------+---------+\n| Conversion | Meaning | Notes |\n+==============+=======================================================+=========+\n| ``\'d\'`` | Signed integer decimal. | |\n+--------------+-------------------------------------------------------+---------+\n| ``\'i\'`` | Signed integer decimal. | |\n+--------------+-------------------------------------------------------+---------+\n| ``\'o\'`` | Signed octal value. | (1) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'u\'`` | Obsolete type -- it is identical to ``\'d\'``. | (7) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'x\'`` | Signed hexadecimal (lowercase). | (2) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'X\'`` | Signed hexadecimal (uppercase). | (2) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'e\'`` | Floating point exponential format (lowercase). | (3) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'E\'`` | Floating point exponential format (uppercase). | (3) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'f\'`` | Floating point decimal format. | (3) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'F\'`` | Floating point decimal format. | (3) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'g\'`` | Floating point format. Uses lowercase exponential | (4) |\n| | format if exponent is less than -4 or not less than | |\n| | precision, decimal format otherwise. | |\n+--------------+-------------------------------------------------------+---------+\n| ``\'G\'`` | Floating point format. Uses uppercase exponential | (4) |\n| | format if exponent is less than -4 or not less than | |\n| | precision, decimal format otherwise. | |\n+--------------+-------------------------------------------------------+---------+\n| ``\'c\'`` | Single character (accepts integer or single character | |\n| | string). | |\n+--------------+-------------------------------------------------------+---------+\n| ``\'r\'`` | String (converts any Python object using ``repr()``). | (5) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'s\'`` | String (converts any Python object using ``str()``). | |\n+--------------+-------------------------------------------------------+---------+\n| ``\'%\'`` | No argument is converted, results in a ``\'%\'`` | |\n| | character in the result. | |\n+--------------+-------------------------------------------------------+---------+\n\nNotes:\n\n1. The alternate form causes a leading zero (``\'0\'``) to be inserted\n between left-hand padding and the formatting of the number if the\n leading character of the result is not already a zero.\n\n2. The alternate form causes a leading ``\'0x\'`` or ``\'0X\'`` (depending\n on whether the ``\'x\'`` or ``\'X\'`` format was used) to be inserted\n between left-hand padding and the formatting of the number if the\n leading character of the result is not already a zero.\n\n3. The alternate form causes the result to always contain a decimal\n point, even if no digits follow it.\n\n The precision determines the number of digits after the decimal\n point and defaults to 6.\n\n4. The alternate form causes the result to always contain a decimal\n point, and trailing zeroes are not removed as they would otherwise\n be.\n\n The precision determines the number of significant digits before\n and after the decimal point and defaults to 6.\n\n5. The precision determines the maximal number of characters used.\n\n1. See **PEP 237**.\n\nSince Python strings have an explicit length, ``%s`` conversions do\nnot assume that ``\'\\0\'`` is the end of the string.\n\nChanged in version 3.1: ``%f`` conversions for numbers whose absolute\nvalue is over 1e50 are no longer replaced by ``%g`` conversions.\n\nAdditional string operations are defined in standard modules\n``string`` and ``re``.\n\n\nRange Type\n==========\n\nThe ``range`` type is an immutable sequence which is commonly used for\nlooping. The advantage of the ``range`` type is that an ``range``\nobject will always take the same amount of memory, no matter the size\nof the range it represents. There are no consistent performance\nadvantages.\n\nRange objects have very little behavior: they only support indexing,\niteration, and the ``len()`` function.\n\n\nMutable Sequence Types\n======================\n\nList and bytearray objects support additional operations that allow\nin-place modification of the object. Other mutable sequence types\n(when added to the language) should also support these operations.\nStrings and tuples are immutable sequence types: such objects cannot\nbe modified once created. The following operations are defined on\nmutable sequence types (where *x* is an arbitrary object).\n\nNote that while lists allow their items to be of any type, bytearray\nobject "items" are all integers in the range 0 <= x < 256.\n\n+--------------------------------+----------------------------------+-----------------------+\n| Operation | Result | Notes |\n+================================+==================================+=======================+\n| ``s[i] = x`` | item *i* of *s* is replaced by | |\n| | *x* | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s[i:j] = t`` | slice of *s* from *i* to *j* is | |\n| | replaced by the contents of the | |\n| | iterable *t* | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``del s[i:j]`` | same as ``s[i:j] = []`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s[i:j:k] = t`` | the elements of ``s[i:j:k]`` are | (1) |\n| | replaced by those of *t* | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``del s[i:j:k]`` | removes the elements of | |\n| | ``s[i:j:k]`` from the list | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.append(x)`` | same as ``s[len(s):len(s)] = | |\n| | [x]`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.extend(x)`` | same as ``s[len(s):len(s)] = x`` | (2) |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.count(x)`` | return number of *i*\'s for which | |\n| | ``s[i] == x`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.index(x[, i[, j]])`` | return smallest *k* such that | (3) |\n| | ``s[k] == x`` and ``i <= k < j`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.insert(i, x)`` | same as ``s[i:i] = [x]`` | (4) |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.pop([i])`` | same as ``x = s[i]; del s[i]; | (5) |\n| | return x`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.remove(x)`` | same as ``del s[s.index(x)]`` | (3) |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.reverse()`` | reverses the items of *s* in | (6) |\n| | place | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.sort([key[, reverse]])`` | sort the items of *s* in place | (6), (7), (8) |\n+--------------------------------+----------------------------------+-----------------------+\n\nNotes:\n\n1. *t* must have the same length as the slice it is replacing.\n\n2. *x* can be any iterable object.\n\n3. Raises ``ValueError`` when *x* is not found in *s*. When a negative\n index is passed as the second or third parameter to the ``index()``\n method, the sequence length is added, as for slice indices. If it\n is still negative, it is truncated to zero, as for slice indices.\n\n4. When a negative index is passed as the first parameter to the\n ``insert()`` method, the sequence length is added, as for slice\n indices. If it is still negative, it is truncated to zero, as for\n slice indices.\n\n5. The optional argument *i* defaults to ``-1``, so that by default\n the last item is removed and returned.\n\n6. The ``sort()`` and ``reverse()`` methods modify the sequence in\n place for economy of space when sorting or reversing a large\n sequence. To remind you that they operate by side effect, they\n don\'t return the sorted or reversed sequence.\n\n7. The ``sort()`` method takes optional arguments for controlling the\n comparisons. Each must be specified as a keyword argument.\n\n *key* specifies a function of one argument that is used to extract\n a comparison key from each list element: ``key=str.lower``. The\n default value is ``None``.\n\n *reverse* is a boolean value. If set to ``True``, then the list\n elements are sorted as if each comparison were reversed.\n\n The ``sort()`` method is guaranteed to be stable. A sort is stable\n if it guarantees not to change the relative order of elements that\n compare equal --- this is helpful for sorting in multiple passes\n (for example, sort by department, then by salary grade).\n\n **CPython implementation detail:** While a list is being sorted,\n the effect of attempting to mutate, or even inspect, the list is\n undefined. The C implementation of Python makes the list appear\n empty for the duration, and raises ``ValueError`` if it can detect\n that the list has been mutated during a sort.\n\n8. ``sort()`` is not supported by ``bytearray`` objects.\n\n\nBytes and Byte Array Methods\n============================\n\nBytes and bytearray objects, being "strings of bytes", have all\nmethods found on strings, with the exception of ``encode()``,\n``format()`` and ``isidentifier()``, which do not make sense with\nthese types. For converting the objects to strings, they have a\n``decode()`` method.\n\nWherever one of these methods needs to interpret the bytes as\ncharacters (e.g. the ``is...()`` methods), the ASCII character set is\nassumed.\n\nNote: The methods on bytes and bytearray objects don\'t accept strings as\n their arguments, just as the methods on strings don\'t accept bytes\n as their arguments. For example, you have to write\n\n a = "abc"\n b = a.replace("a", "f")\n\n and\n\n a = b"abc"\n b = a.replace(b"a", b"f")\n\nbytes.decode([encoding[, errors]])\nbytearray.decode([encoding[, errors]])\n\n Return a string decoded from the given bytes. Default encoding is\n the current default string encoding. *errors* may be given to set\n a different error handling scheme. The default for *errors* is\n ``\'strict\'``, meaning that encoding errors raise a\n ``UnicodeError``. Other possible values are ``\'ignore\'``,\n ``\'replace\'`` and any other name registered via\n ``codecs.register_error()``, see section *Codec Base Classes*. For\n a list of possible encodings, see section *Standard Encodings*.\n\nThe bytes and bytearray types have an additional class method:\n\nclassmethod bytes.fromhex(string)\nclassmethod bytearray.fromhex(string)\n\n This ``bytes`` class method returns a bytes or bytearray object,\n decoding the given string object. The string must contain two\n hexadecimal digits per byte, spaces are ignored.\n\n >>> bytes.fromhex(\'f0 f1f2 \')\n b\'\\xf0\\xf1\\xf2\'\n\nThe maketrans and translate methods differ in semantics from the\nversions available on strings:\n\nbytes.translate(table[, delete])\nbytearray.translate(table[, delete])\n\n Return a copy of the bytes or bytearray object where all bytes\n occurring in the optional argument *delete* are removed, and the\n remaining bytes have been mapped through the given translation\n table, which must be a bytes object of length 256.\n\n You can use the ``bytes.maketrans()`` method to create a\n translation table.\n\n Set the *table* argument to ``None`` for translations that only\n delete characters:\n\n >>> b\'read this short text\'.translate(None, b\'aeiou\')\n b\'rd ths shrt txt\'\n\nstatic bytes.maketrans(from, to)\nstatic bytearray.maketrans(from, to)\n\n This static method returns a translation table usable for\n ``bytes.translate()`` that will map each character in *from* into\n the character at the same position in *to*; *from* and *to* must be\n bytes objects and have the same length.\n\n New in version 3.1.\n', + 'typesseq-mutable': '\nMutable Sequence Types\n**********************\n\nList and bytearray objects support additional operations that allow\nin-place modification of the object. Other mutable sequence types\n(when added to the language) should also support these operations.\nStrings and tuples are immutable sequence types: such objects cannot\nbe modified once created. The following operations are defined on\nmutable sequence types (where *x* is an arbitrary object).\n\nNote that while lists allow their items to be of any type, bytearray\nobject "items" are all integers in the range 0 <= x < 256.\n\n+--------------------------------+----------------------------------+-----------------------+\n| Operation | Result | Notes |\n+================================+==================================+=======================+\n| ``s[i] = x`` | item *i* of *s* is replaced by | |\n| | *x* | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s[i:j] = t`` | slice of *s* from *i* to *j* is | |\n| | replaced by the contents of the | |\n| | iterable *t* | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``del s[i:j]`` | same as ``s[i:j] = []`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s[i:j:k] = t`` | the elements of ``s[i:j:k]`` are | (1) |\n| | replaced by those of *t* | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``del s[i:j:k]`` | removes the elements of | |\n| | ``s[i:j:k]`` from the list | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.append(x)`` | same as ``s[len(s):len(s)] = | |\n| | [x]`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.extend(x)`` | same as ``s[len(s):len(s)] = x`` | (2) |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.count(x)`` | return number of *i*\'s for which | |\n| | ``s[i] == x`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.index(x[, i[, j]])`` | return smallest *k* such that | (3) |\n| | ``s[k] == x`` and ``i <= k < j`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.insert(i, x)`` | same as ``s[i:i] = [x]`` | (4) |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.pop([i])`` | same as ``x = s[i]; del s[i]; | (5) |\n| | return x`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.remove(x)`` | same as ``del s[s.index(x)]`` | (3) |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.reverse()`` | reverses the items of *s* in | (6) |\n| | place | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.sort([key[, reverse]])`` | sort the items of *s* in place | (6), (7), (8) |\n+--------------------------------+----------------------------------+-----------------------+\n\nNotes:\n\n1. *t* must have the same length as the slice it is replacing.\n\n2. *x* can be any iterable object.\n\n3. Raises ``ValueError`` when *x* is not found in *s*. When a negative\n index is passed as the second or third parameter to the ``index()``\n method, the sequence length is added, as for slice indices. If it\n is still negative, it is truncated to zero, as for slice indices.\n\n4. When a negative index is passed as the first parameter to the\n ``insert()`` method, the sequence length is added, as for slice\n indices. If it is still negative, it is truncated to zero, as for\n slice indices.\n\n5. The optional argument *i* defaults to ``-1``, so that by default\n the last item is removed and returned.\n\n6. The ``sort()`` and ``reverse()`` methods modify the sequence in\n place for economy of space when sorting or reversing a large\n sequence. To remind you that they operate by side effect, they\n don\'t return the sorted or reversed sequence.\n\n7. The ``sort()`` method takes optional arguments for controlling the\n comparisons. Each must be specified as a keyword argument.\n\n *key* specifies a function of one argument that is used to extract\n a comparison key from each list element: ``key=str.lower``. The\n default value is ``None``.\n\n *reverse* is a boolean value. If set to ``True``, then the list\n elements are sorted as if each comparison were reversed.\n\n The ``sort()`` method is guaranteed to be stable. A sort is stable\n if it guarantees not to change the relative order of elements that\n compare equal --- this is helpful for sorting in multiple passes\n (for example, sort by department, then by salary grade).\n\n **CPython implementation detail:** While a list is being sorted,\n the effect of attempting to mutate, or even inspect, the list is\n undefined. The C implementation of Python makes the list appear\n empty for the duration, and raises ``ValueError`` if it can detect\n that the list has been mutated during a sort.\n\n8. ``sort()`` is not supported by ``bytearray`` objects.\n', 'unary': '\nUnary arithmetic and bitwise operations\n***************************************\n\nAll unary arithmetic and bitwise operations have the same priority:\n\n u_expr ::= power | "-" u_expr | "+" u_expr | "~" u_expr\n\nThe unary ``-`` (minus) operator yields the negation of its numeric\nargument.\n\nThe unary ``+`` (plus) operator yields its numeric argument unchanged.\n\nThe unary ``~`` (invert) operator yields the bitwise inversion of its\ninteger argument. The bitwise inversion of ``x`` is defined as\n``-(x+1)``. It only applies to integral numbers.\n\nIn all three cases, if the argument does not have the proper type, a\n``TypeError`` exception is raised.\n', 'while': '\nThe ``while`` statement\n***********************\n\nThe ``while`` statement is used for repeated execution as long as an\nexpression is true:\n\n while_stmt ::= "while" expression ":" suite\n ["else" ":" suite]\n\nThis repeatedly tests the expression and, if it is true, executes the\nfirst suite; if the expression is false (which may be the first time\nit is tested) the suite of the ``else`` clause, if present, is\nexecuted and the loop terminates.\n\nA ``break`` statement executed in the first suite terminates the loop\nwithout executing the ``else`` clause\'s suite. A ``continue``\nstatement executed in the first suite skips the rest of the suite and\ngoes back to testing the expression.\n', - 'with': '\nThe ``with`` statement\n**********************\n\nThe ``with`` statement is used to wrap the execution of a block with\nmethods defined by a context manager (see section *With Statement\nContext Managers*). This allows common\n``try``...``except``...``finally`` usage patterns to be encapsulated\nfor convenient reuse.\n\n with_stmt ::= "with" with_item ("," with_item)* ":" suite\n with_item ::= expression ["as" target]\n\nThe execution of the ``with`` statement with one "item" proceeds as\nfollows:\n\n1. The context expression is evaluated to obtain a context manager.\n\n2. The context manager\'s ``__enter__()`` method is invoked.\n\n3. If a target was included in the ``with`` statement, the return\n value from ``__enter__()`` is assigned to it.\n\n Note: The ``with`` statement guarantees that if the ``__enter__()``\n method returns without an error, then ``__exit__()`` will always\n be called. Thus, if an error occurs during the assignment to the\n target list, it will be treated the same as an error occurring\n within the suite would be. See step 5 below.\n\n4. The suite is executed.\n\n5. The context manager\'s ``__exit__()`` method is invoked. If an\n exception caused the suite to be exited, its type, value, and\n traceback are passed as arguments to ``__exit__()``. Otherwise,\n three ``None`` arguments are supplied.\n\n If the suite was exited due to an exception, and the return value\n from the ``__exit__()`` method was false, the exception is\n reraised. If the return value was true, the exception is\n suppressed, and execution continues with the statement following\n the ``with`` statement.\n\n If the suite was exited for any reason other than an exception, the\n return value from ``__exit__()`` is ignored, and execution proceeds\n at the normal location for the kind of exit that was taken.\n\nWith more than one item, the context managers are processed as if\nmultiple ``with`` statements were nested:\n\n with A() as a, B() as b:\n suite\n\nis equivalent to\n\n with A() as a:\n with B() as b:\n suite\n\nChanged in version 3.1: Support for multiple context expressions.\n\nSee also:\n\n **PEP 0343** - The "with" statement\n The specification, background, and examples for the Python\n ``with`` statement.\n', + 'with': '\nThe ``with`` statement\n**********************\n\nThe ``with`` statement is used to wrap the execution of a block with\nmethods defined by a context manager (see section *With Statement\nContext Managers*). This allows common\n``try``...``except``...``finally`` usage patterns to be encapsulated\nfor convenient reuse.\n\n with_stmt ::= "with" with_item ("," with_item)* ":" suite\n with_item ::= expression ["as" target]\n\nThe execution of the ``with`` statement with one "item" proceeds as\nfollows:\n\n1. The context expression (the expression given in the **with_item**)\n is evaluated to obtain a context manager.\n\n2. The context manager\'s ``__enter__()`` method is invoked.\n\n3. If a target was included in the ``with`` statement, the return\n value from ``__enter__()`` is assigned to it.\n\n Note: The ``with`` statement guarantees that if the ``__enter__()``\n method returns without an error, then ``__exit__()`` will always\n be called. Thus, if an error occurs during the assignment to the\n target list, it will be treated the same as an error occurring\n within the suite would be. See step 5 below.\n\n4. The suite is executed.\n\n5. The context manager\'s ``__exit__()`` method is invoked. If an\n exception caused the suite to be exited, its type, value, and\n traceback are passed as arguments to ``__exit__()``. Otherwise,\n three ``None`` arguments are supplied.\n\n If the suite was exited due to an exception, and the return value\n from the ``__exit__()`` method was false, the exception is\n reraised. If the return value was true, the exception is\n suppressed, and execution continues with the statement following\n the ``with`` statement.\n\n If the suite was exited for any reason other than an exception, the\n return value from ``__exit__()`` is ignored, and execution proceeds\n at the normal location for the kind of exit that was taken.\n\nWith more than one item, the context managers are processed as if\nmultiple ``with`` statements were nested:\n\n with A() as a, B() as b:\n suite\n\nis equivalent to\n\n with A() as a:\n with B() as b:\n suite\n\nChanged in version 3.1: Support for multiple context expressions.\n\nSee also:\n\n **PEP 0343** - The "with" statement\n The specification, background, and examples for the Python\n ``with`` statement.\n', 'yield': '\nThe ``yield`` statement\n***********************\n\n yield_stmt ::= yield_expression\n\nThe ``yield`` statement is only used when defining a generator\nfunction, and is only used in the body of the generator function.\nUsing a ``yield`` statement in a function definition is sufficient to\ncause that definition to create a generator function instead of a\nnormal function. When a generator function is called, it returns an\niterator known as a generator iterator, or more commonly, a generator.\nThe body of the generator function is executed by calling the\n``next()`` function on the generator repeatedly until it raises an\nexception.\n\nWhen a ``yield`` statement is executed, the state of the generator is\nfrozen and the value of **expression_list** is returned to\n``next()``\'s caller. By "frozen" we mean that all local state is\nretained, including the current bindings of local variables, the\ninstruction pointer, and the internal evaluation stack: enough\ninformation is saved so that the next time ``next()`` is invoked, the\nfunction can proceed exactly as if the ``yield`` statement were just\nanother external call.\n\nThe ``yield`` statement is allowed in the ``try`` clause of a ``try``\n... ``finally`` construct. If the generator is not resumed before it\nis finalized (by reaching a zero reference count or by being garbage\ncollected), the generator-iterator\'s ``close()`` method will be\ncalled, allowing any pending ``finally`` clauses to execute.\n\nSee also:\n\n **PEP 0255** - Simple Generators\n The proposal for adding generators and the ``yield`` statement\n to Python.\n\n **PEP 0342** - Coroutines via Enhanced Generators\n The proposal that, among other generator enhancements, proposed\n allowing ``yield`` to appear inside a ``try`` ... ``finally``\n block.\n'} diff --git a/Lib/test/test_pydoc.py b/Lib/test/test_pydoc.py --- a/Lib/test/test_pydoc.py +++ b/Lib/test/test_pydoc.py @@ -6,6 +6,7 @@ import re import pydoc import inspect +import keyword import unittest import test.support import xml.etree @@ -344,8 +345,13 @@ self.assertTrue(expected in pydoc.render_doc(c)) +class TestHelper(unittest.TestCase): + def test_keywords(self): + self.assertEqual(sorted(pydoc.Helper.keywords), + sorted(keyword.kwlist)) + def test_main(): - test.support.run_unittest(PyDocDocTest, TestDescriptions) + test.support.run_unittest(PyDocDocTest, TestDescriptions, TestHelper) if __name__ == "__main__": test_main() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Apr 28 06:59:48 2011 From: python-checkins at python.org (ezio.melotti) Date: Thu, 28 Apr 2011 06:59:48 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): #11926: merge with 3.1. Message-ID: http://hg.python.org/cpython/rev/7b4c853aa07d changeset: 69650:7b4c853aa07d branch: 3.2 parent: 69646:08647ab0ead7 parent: 69649:99d5542399a1 user: Ezio Melotti date: Thu Apr 28 07:51:14 2011 +0300 summary: #11926: merge with 3.1. files: Lib/pydoc.py | 6 ++++++ Lib/pydoc_data/topics.py | 20 ++++++++++---------- Lib/test/test_pydoc.py | 7 +++++++ 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/Lib/pydoc.py b/Lib/pydoc.py --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -1576,6 +1576,9 @@ # in Doc/ and copying the output file into the Lib/ directory. keywords = { + 'False': '', + 'None': '', + 'True': '', 'and': 'BOOLEAN', 'as': 'with', 'assert': ('assert', ''), @@ -1791,6 +1794,9 @@ elif request[:8] == 'modules ': self.listmodules(request.split()[1]) elif request in self.symbols: self.showsymbol(request) + elif request in ['True', 'False', 'None']: + # special case these keywords since they are objects too + doc(eval(request), 'Help on %s:') elif request in self.keywords: self.showtopic(request) elif request in self.topics: self.showtopic(request) elif request: doc(request, 'Help on %s:', output=self._output) diff --git a/Lib/pydoc_data/topics.py b/Lib/pydoc_data/topics.py --- a/Lib/pydoc_data/topics.py +++ b/Lib/pydoc_data/topics.py @@ -1,9 +1,9 @@ -# Autogenerated by Sphinx on Sun Feb 20 10:16:17 2011 +# Autogenerated by Sphinx on Thu Apr 28 07:47:47 2011 topics = {'assert': '\nThe ``assert`` statement\n************************\n\nAssert statements are a convenient way to insert debugging assertions\ninto a program:\n\n assert_stmt ::= "assert" expression ["," expression]\n\nThe simple form, ``assert expression``, is equivalent to\n\n if __debug__:\n if not expression: raise AssertionError\n\nThe extended form, ``assert expression1, expression2``, is equivalent\nto\n\n if __debug__:\n if not expression1: raise AssertionError(expression2)\n\nThese equivalences assume that ``__debug__`` and ``AssertionError``\nrefer to the built-in variables with those names. In the current\nimplementation, the built-in variable ``__debug__`` is ``True`` under\nnormal circumstances, ``False`` when optimization is requested\n(command line option -O). The current code generator emits no code\nfor an assert statement when optimization is requested at compile\ntime. Note that it is unnecessary to include the source code for the\nexpression that failed in the error message; it will be displayed as\npart of the stack trace.\n\nAssignments to ``__debug__`` are illegal. The value for the built-in\nvariable is determined when the interpreter starts.\n', - 'assignment': '\nAssignment statements\n*********************\n\nAssignment statements are used to (re)bind names to values and to\nmodify attributes or items of mutable objects:\n\n assignment_stmt ::= (target_list "=")+ (expression_list | yield_expression)\n target_list ::= target ("," target)* [","]\n target ::= identifier\n | "(" target_list ")"\n | "[" target_list "]"\n | attributeref\n | subscription\n | slicing\n | "*" target\n\n(See section *Primaries* for the syntax definitions for the last three\nsymbols.)\n\nAn assignment statement evaluates the expression list (remember that\nthis can be a single expression or a comma-separated list, the latter\nyielding a tuple) and assigns the single resulting object to each of\nthe target lists, from left to right.\n\nAssignment is defined recursively depending on the form of the target\n(list). When a target is part of a mutable object (an attribute\nreference, subscription or slicing), the mutable object must\nultimately perform the assignment and decide about its validity, and\nmay raise an exception if the assignment is unacceptable. The rules\nobserved by various types and the exceptions raised are given with the\ndefinition of the object types (see section *The standard type\nhierarchy*).\n\nAssignment of an object to a target list, optionally enclosed in\nparentheses or square brackets, is recursively defined as follows.\n\n* If the target list is a single target: The object is assigned to\n that target.\n\n* If the target list is a comma-separated list of targets: The object\n must be an iterable with the same number of items as there are\n targets in the target list, and the items are assigned, from left to\n right, to the corresponding targets. (This rule is relaxed as of\n Python 1.5; in earlier versions, the object had to be a tuple.\n Since strings are sequences, an assignment like ``a, b = "xy"`` is\n now legal as long as the string has the right length.)\n\n * If the target list contains one target prefixed with an asterisk,\n called a "starred" target: The object must be a sequence with at\n least as many items as there are targets in the target list, minus\n one. The first items of the sequence are assigned, from left to\n right, to the targets before the starred target. The final items\n of the sequence are assigned to the targets after the starred\n target. A list of the remaining items in the sequence is then\n assigned to the starred target (the list can be empty).\n\n * Else: The object must be a sequence with the same number of items\n as there are targets in the target list, and the items are\n assigned, from left to right, to the corresponding targets.\n\nAssignment of an object to a single target is recursively defined as\nfollows.\n\n* If the target is an identifier (name):\n\n * If the name does not occur in a ``global`` or ``nonlocal``\n statement in the current code block: the name is bound to the\n object in the current local namespace.\n\n * Otherwise: the name is bound to the object in the global namespace\n or the outer namespace determined by ``nonlocal``, respectively.\n\n The name is rebound if it was already bound. This may cause the\n reference count for the object previously bound to the name to reach\n zero, causing the object to be deallocated and its destructor (if it\n has one) to be called.\n\n* If the target is a target list enclosed in parentheses or in square\n brackets: The object must be an iterable with the same number of\n items as there are targets in the target list, and its items are\n assigned, from left to right, to the corresponding targets.\n\n* If the target is an attribute reference: The primary expression in\n the reference is evaluated. It should yield an object with\n assignable attributes; if this is not the case, ``TypeError`` is\n raised. That object is then asked to assign the assigned object to\n the given attribute; if it cannot perform the assignment, it raises\n an exception (usually but not necessarily ``AttributeError``).\n\n Note: If the object is a class instance and the attribute reference\n occurs on both sides of the assignment operator, the RHS expression,\n ``a.x`` can access either an instance attribute or (if no instance\n attribute exists) a class attribute. The LHS target ``a.x`` is\n always set as an instance attribute, creating it if necessary.\n Thus, the two occurrences of ``a.x`` do not necessarily refer to the\n same attribute: if the RHS expression refers to a class attribute,\n the LHS creates a new instance attribute as the target of the\n assignment:\n\n class Cls:\n x = 3 # class variable\n inst = Cls()\n inst.x = inst.x + 1 # writes inst.x as 4 leaving Cls.x as 3\n\n This description does not necessarily apply to descriptor\n attributes, such as properties created with ``property()``.\n\n* If the target is a subscription: The primary expression in the\n reference is evaluated. It should yield either a mutable sequence\n object (such as a list) or a mapping object (such as a dictionary).\n Next, the subscript expression is evaluated.\n\n If the primary is a mutable sequence object (such as a list), the\n subscript must yield an integer. If it is negative, the sequence\'s\n length is added to it. The resulting value must be a nonnegative\n integer less than the sequence\'s length, and the sequence is asked\n to assign the assigned object to its item with that index. If the\n index is out of range, ``IndexError`` is raised (assignment to a\n subscripted sequence cannot add new items to a list).\n\n If the primary is a mapping object (such as a dictionary), the\n subscript must have a type compatible with the mapping\'s key type,\n and the mapping is then asked to create a key/datum pair which maps\n the subscript to the assigned object. This can either replace an\n existing key/value pair with the same key value, or insert a new\n key/value pair (if no key with the same value existed).\n\n For user-defined objects, the ``__setitem__()`` method is called\n with appropriate arguments.\n\n* If the target is a slicing: The primary expression in the reference\n is evaluated. It should yield a mutable sequence object (such as a\n list). The assigned object should be a sequence object of the same\n type. Next, the lower and upper bound expressions are evaluated,\n insofar they are present; defaults are zero and the sequence\'s\n length. The bounds should evaluate to integers. If either bound is\n negative, the sequence\'s length is added to it. The resulting\n bounds are clipped to lie between zero and the sequence\'s length,\n inclusive. Finally, the sequence object is asked to replace the\n slice with the items of the assigned sequence. The length of the\n slice may be different from the length of the assigned sequence,\n thus changing the length of the target sequence, if the object\n allows it.\n\n**CPython implementation detail:** In the current implementation, the\nsyntax for targets is taken to be the same as for expressions, and\ninvalid syntax is rejected during the code generation phase, causing\nless detailed error messages.\n\nWARNING: Although the definition of assignment implies that overlaps\nbetween the left-hand side and the right-hand side are \'safe\' (for\nexample ``a, b = b, a`` swaps two variables), overlaps *within* the\ncollection of assigned-to variables are not safe! For instance, the\nfollowing program prints ``[0, 2]``:\n\n x = [0, 1]\n i = 0\n i, x[i] = 1, 2\n print(x)\n\nSee also:\n\n **PEP 3132** - Extended Iterable Unpacking\n The specification for the ``*target`` feature.\n\n\nAugmented assignment statements\n===============================\n\nAugmented assignment is the combination, in a single statement, of a\nbinary operation and an assignment statement:\n\n augmented_assignment_stmt ::= augtarget augop (expression_list | yield_expression)\n augtarget ::= identifier | attributeref | subscription | slicing\n augop ::= "+=" | "-=" | "*=" | "/=" | "//=" | "%=" | "**="\n | ">>=" | "<<=" | "&=" | "^=" | "|="\n\n(See section *Primaries* for the syntax definitions for the last three\nsymbols.)\n\nAn augmented assignment evaluates the target (which, unlike normal\nassignment statements, cannot be an unpacking) and the expression\nlist, performs the binary operation specific to the type of assignment\non the two operands, and assigns the result to the original target.\nThe target is only evaluated once.\n\nAn augmented assignment expression like ``x += 1`` can be rewritten as\n``x = x + 1`` to achieve a similar, but not exactly equal effect. In\nthe augmented version, ``x`` is only evaluated once. Also, when\npossible, the actual operation is performed *in-place*, meaning that\nrather than creating a new object and assigning that to the target,\nthe old object is modified instead.\n\nWith the exception of assigning to tuples and multiple targets in a\nsingle statement, the assignment done by augmented assignment\nstatements is handled the same way as normal assignments. Similarly,\nwith the exception of the possible *in-place* behavior, the binary\noperation performed by augmented assignment is the same as the normal\nbinary operations.\n\nFor targets which are attribute references, the same *caveat about\nclass and instance attributes* applies as for regular assignments.\n', + 'assignment': '\nAssignment statements\n*********************\n\nAssignment statements are used to (re)bind names to values and to\nmodify attributes or items of mutable objects:\n\n assignment_stmt ::= (target_list "=")+ (expression_list | yield_expression)\n target_list ::= target ("," target)* [","]\n target ::= identifier\n | "(" target_list ")"\n | "[" target_list "]"\n | attributeref\n | subscription\n | slicing\n | "*" target\n\n(See section *Primaries* for the syntax definitions for the last three\nsymbols.)\n\nAn assignment statement evaluates the expression list (remember that\nthis can be a single expression or a comma-separated list, the latter\nyielding a tuple) and assigns the single resulting object to each of\nthe target lists, from left to right.\n\nAssignment is defined recursively depending on the form of the target\n(list). When a target is part of a mutable object (an attribute\nreference, subscription or slicing), the mutable object must\nultimately perform the assignment and decide about its validity, and\nmay raise an exception if the assignment is unacceptable. The rules\nobserved by various types and the exceptions raised are given with the\ndefinition of the object types (see section *The standard type\nhierarchy*).\n\nAssignment of an object to a target list, optionally enclosed in\nparentheses or square brackets, is recursively defined as follows.\n\n* If the target list is a single target: The object is assigned to\n that target.\n\n* If the target list is a comma-separated list of targets: The object\n must be an iterable with the same number of items as there are\n targets in the target list, and the items are assigned, from left to\n right, to the corresponding targets.\n\n * If the target list contains one target prefixed with an asterisk,\n called a "starred" target: The object must be a sequence with at\n least as many items as there are targets in the target list, minus\n one. The first items of the sequence are assigned, from left to\n right, to the targets before the starred target. The final items\n of the sequence are assigned to the targets after the starred\n target. A list of the remaining items in the sequence is then\n assigned to the starred target (the list can be empty).\n\n * Else: The object must be a sequence with the same number of items\n as there are targets in the target list, and the items are\n assigned, from left to right, to the corresponding targets.\n\nAssignment of an object to a single target is recursively defined as\nfollows.\n\n* If the target is an identifier (name):\n\n * If the name does not occur in a ``global`` or ``nonlocal``\n statement in the current code block: the name is bound to the\n object in the current local namespace.\n\n * Otherwise: the name is bound to the object in the global namespace\n or the outer namespace determined by ``nonlocal``, respectively.\n\n The name is rebound if it was already bound. This may cause the\n reference count for the object previously bound to the name to reach\n zero, causing the object to be deallocated and its destructor (if it\n has one) to be called.\n\n* If the target is a target list enclosed in parentheses or in square\n brackets: The object must be an iterable with the same number of\n items as there are targets in the target list, and its items are\n assigned, from left to right, to the corresponding targets.\n\n* If the target is an attribute reference: The primary expression in\n the reference is evaluated. It should yield an object with\n assignable attributes; if this is not the case, ``TypeError`` is\n raised. That object is then asked to assign the assigned object to\n the given attribute; if it cannot perform the assignment, it raises\n an exception (usually but not necessarily ``AttributeError``).\n\n Note: If the object is a class instance and the attribute reference\n occurs on both sides of the assignment operator, the RHS expression,\n ``a.x`` can access either an instance attribute or (if no instance\n attribute exists) a class attribute. The LHS target ``a.x`` is\n always set as an instance attribute, creating it if necessary.\n Thus, the two occurrences of ``a.x`` do not necessarily refer to the\n same attribute: if the RHS expression refers to a class attribute,\n the LHS creates a new instance attribute as the target of the\n assignment:\n\n class Cls:\n x = 3 # class variable\n inst = Cls()\n inst.x = inst.x + 1 # writes inst.x as 4 leaving Cls.x as 3\n\n This description does not necessarily apply to descriptor\n attributes, such as properties created with ``property()``.\n\n* If the target is a subscription: The primary expression in the\n reference is evaluated. It should yield either a mutable sequence\n object (such as a list) or a mapping object (such as a dictionary).\n Next, the subscript expression is evaluated.\n\n If the primary is a mutable sequence object (such as a list), the\n subscript must yield an integer. If it is negative, the sequence\'s\n length is added to it. The resulting value must be a nonnegative\n integer less than the sequence\'s length, and the sequence is asked\n to assign the assigned object to its item with that index. If the\n index is out of range, ``IndexError`` is raised (assignment to a\n subscripted sequence cannot add new items to a list).\n\n If the primary is a mapping object (such as a dictionary), the\n subscript must have a type compatible with the mapping\'s key type,\n and the mapping is then asked to create a key/datum pair which maps\n the subscript to the assigned object. This can either replace an\n existing key/value pair with the same key value, or insert a new\n key/value pair (if no key with the same value existed).\n\n For user-defined objects, the ``__setitem__()`` method is called\n with appropriate arguments.\n\n* If the target is a slicing: The primary expression in the reference\n is evaluated. It should yield a mutable sequence object (such as a\n list). The assigned object should be a sequence object of the same\n type. Next, the lower and upper bound expressions are evaluated,\n insofar they are present; defaults are zero and the sequence\'s\n length. The bounds should evaluate to integers. If either bound is\n negative, the sequence\'s length is added to it. The resulting\n bounds are clipped to lie between zero and the sequence\'s length,\n inclusive. Finally, the sequence object is asked to replace the\n slice with the items of the assigned sequence. The length of the\n slice may be different from the length of the assigned sequence,\n thus changing the length of the target sequence, if the object\n allows it.\n\n**CPython implementation detail:** In the current implementation, the\nsyntax for targets is taken to be the same as for expressions, and\ninvalid syntax is rejected during the code generation phase, causing\nless detailed error messages.\n\nWARNING: Although the definition of assignment implies that overlaps\nbetween the left-hand side and the right-hand side are \'safe\' (for\nexample ``a, b = b, a`` swaps two variables), overlaps *within* the\ncollection of assigned-to variables are not safe! For instance, the\nfollowing program prints ``[0, 2]``:\n\n x = [0, 1]\n i = 0\n i, x[i] = 1, 2\n print(x)\n\nSee also:\n\n **PEP 3132** - Extended Iterable Unpacking\n The specification for the ``*target`` feature.\n\n\nAugmented assignment statements\n===============================\n\nAugmented assignment is the combination, in a single statement, of a\nbinary operation and an assignment statement:\n\n augmented_assignment_stmt ::= augtarget augop (expression_list | yield_expression)\n augtarget ::= identifier | attributeref | subscription | slicing\n augop ::= "+=" | "-=" | "*=" | "/=" | "//=" | "%=" | "**="\n | ">>=" | "<<=" | "&=" | "^=" | "|="\n\n(See section *Primaries* for the syntax definitions for the last three\nsymbols.)\n\nAn augmented assignment evaluates the target (which, unlike normal\nassignment statements, cannot be an unpacking) and the expression\nlist, performs the binary operation specific to the type of assignment\non the two operands, and assigns the result to the original target.\nThe target is only evaluated once.\n\nAn augmented assignment expression like ``x += 1`` can be rewritten as\n``x = x + 1`` to achieve a similar, but not exactly equal effect. In\nthe augmented version, ``x`` is only evaluated once. Also, when\npossible, the actual operation is performed *in-place*, meaning that\nrather than creating a new object and assigning that to the target,\nthe old object is modified instead.\n\nWith the exception of assigning to tuples and multiple targets in a\nsingle statement, the assignment done by augmented assignment\nstatements is handled the same way as normal assignments. Similarly,\nwith the exception of the possible *in-place* behavior, the binary\noperation performed by augmented assignment is the same as the normal\nbinary operations.\n\nFor targets which are attribute references, the same *caveat about\nclass and instance attributes* applies as for regular assignments.\n', 'atom-identifiers': '\nIdentifiers (Names)\n*******************\n\nAn identifier occurring as an atom is a name. See section\n*Identifiers and keywords* for lexical definition and section *Naming\nand binding* for documentation of naming and binding.\n\nWhen the name is bound to an object, evaluation of the atom yields\nthat object. When a name is not bound, an attempt to evaluate it\nraises a ``NameError`` exception.\n\n**Private name mangling:** When an identifier that textually occurs in\na class definition begins with two or more underscore characters and\ndoes not end in two or more underscores, it is considered a *private\nname* of that class. Private names are transformed to a longer form\nbefore code is generated for them. The transformation inserts the\nclass name in front of the name, with leading underscores removed, and\na single underscore inserted in front of the class name. For example,\nthe identifier ``__spam`` occurring in a class named ``Ham`` will be\ntransformed to ``_Ham__spam``. This transformation is independent of\nthe syntactical context in which the identifier is used. If the\ntransformed name is extremely long (longer than 255 characters),\nimplementation defined truncation may happen. If the class name\nconsists only of underscores, no transformation is done.\n', 'atom-literals': "\nLiterals\n********\n\nPython supports string and bytes literals and various numeric\nliterals:\n\n literal ::= stringliteral | bytesliteral\n | integer | floatnumber | imagnumber\n\nEvaluation of a literal yields an object of the given type (string,\nbytes, integer, floating point number, complex number) with the given\nvalue. The value may be approximated in the case of floating point\nand imaginary (complex) literals. See section *Literals* for details.\n\nWith the exception of bytes literals, these all correspond to\nimmutable data types, and hence the object's identity is less\nimportant than its value. Multiple evaluations of literals with the\nsame value (either the same occurrence in the program text or a\ndifferent occurrence) may obtain the same object or a different object\nwith the same value.\n", - 'attribute-access': '\nCustomizing attribute access\n****************************\n\nThe following methods can be defined to customize the meaning of\nattribute access (use of, assignment to, or deletion of ``x.name``)\nfor class instances.\n\nobject.__getattr__(self, name)\n\n Called when an attribute lookup has not found the attribute in the\n usual places (i.e. it is not an instance attribute nor is it found\n in the class tree for ``self``). ``name`` is the attribute name.\n This method should return the (computed) attribute value or raise\n an ``AttributeError`` exception.\n\n Note that if the attribute is found through the normal mechanism,\n ``__getattr__()`` is not called. (This is an intentional asymmetry\n between ``__getattr__()`` and ``__setattr__()``.) This is done both\n for efficiency reasons and because otherwise ``__getattr__()``\n would have no way to access other attributes of the instance. Note\n that at least for instance variables, you can fake total control by\n not inserting any values in the instance attribute dictionary (but\n instead inserting them in another object). See the\n ``__getattribute__()`` method below for a way to actually get total\n control over attribute access.\n\nobject.__getattribute__(self, name)\n\n Called unconditionally to implement attribute accesses for\n instances of the class. If the class also defines\n ``__getattr__()``, the latter will not be called unless\n ``__getattribute__()`` either calls it explicitly or raises an\n ``AttributeError``. This method should return the (computed)\n attribute value or raise an ``AttributeError`` exception. In order\n to avoid infinite recursion in this method, its implementation\n should always call the base class method with the same name to\n access any attributes it needs, for example,\n ``object.__getattribute__(self, name)``.\n\n Note: This method may still be bypassed when looking up special methods\n as the result of implicit invocation via language syntax or\n built-in functions. See *Special method lookup*.\n\nobject.__setattr__(self, name, value)\n\n Called when an attribute assignment is attempted. This is called\n instead of the normal mechanism (i.e. store the value in the\n instance dictionary). *name* is the attribute name, *value* is the\n value to be assigned to it.\n\n If ``__setattr__()`` wants to assign to an instance attribute, it\n should call the base class method with the same name, for example,\n ``object.__setattr__(self, name, value)``.\n\nobject.__delattr__(self, name)\n\n Like ``__setattr__()`` but for attribute deletion instead of\n assignment. This should only be implemented if ``del obj.name`` is\n meaningful for the object.\n\nobject.__dir__(self)\n\n Called when ``dir()`` is called on the object. A list must be\n returned.\n\n\nImplementing Descriptors\n========================\n\nThe following methods only apply when an instance of the class\ncontaining the method (a so-called *descriptor* class) appears in the\nclass dictionary of another class, known as the *owner* class. In the\nexamples below, "the attribute" refers to the attribute whose name is\nthe key of the property in the owner class\' ``__dict__``.\n\nobject.__get__(self, instance, owner)\n\n Called to get the attribute of the owner class (class attribute\n access) or of an instance of that class (instance attribute\n access). *owner* is always the owner class, while *instance* is the\n instance that the attribute was accessed through, or ``None`` when\n the attribute is accessed through the *owner*. This method should\n return the (computed) attribute value or raise an\n ``AttributeError`` exception.\n\nobject.__set__(self, instance, value)\n\n Called to set the attribute on an instance *instance* of the owner\n class to a new value, *value*.\n\nobject.__delete__(self, instance)\n\n Called to delete the attribute on an instance *instance* of the\n owner class.\n\n\nInvoking Descriptors\n====================\n\nIn general, a descriptor is an object attribute with "binding\nbehavior", one whose attribute access has been overridden by methods\nin the descriptor protocol: ``__get__()``, ``__set__()``, and\n``__delete__()``. If any of those methods are defined for an object,\nit is said to be a descriptor.\n\nThe default behavior for attribute access is to get, set, or delete\nthe attribute from an object\'s dictionary. For instance, ``a.x`` has a\nlookup chain starting with ``a.__dict__[\'x\']``, then\n``type(a).__dict__[\'x\']``, and continuing through the base classes of\n``type(a)`` excluding metaclasses.\n\nHowever, if the looked-up value is an object defining one of the\ndescriptor methods, then Python may override the default behavior and\ninvoke the descriptor method instead. Where this occurs in the\nprecedence chain depends on which descriptor methods were defined and\nhow they were called.\n\nThe starting point for descriptor invocation is a binding, ``a.x``.\nHow the arguments are assembled depends on ``a``:\n\nDirect Call\n The simplest and least common call is when user code directly\n invokes a descriptor method: ``x.__get__(a)``.\n\nInstance Binding\n If binding to an object instance, ``a.x`` is transformed into the\n call: ``type(a).__dict__[\'x\'].__get__(a, type(a))``.\n\nClass Binding\n If binding to a class, ``A.x`` is transformed into the call:\n ``A.__dict__[\'x\'].__get__(None, A)``.\n\nSuper Binding\n If ``a`` is an instance of ``super``, then the binding ``super(B,\n obj).m()`` searches ``obj.__class__.__mro__`` for the base class\n ``A`` immediately preceding ``B`` and then invokes the descriptor\n with the call: ``A.__dict__[\'m\'].__get__(obj, A)``.\n\nFor instance bindings, the precedence of descriptor invocation depends\non the which descriptor methods are defined. A descriptor can define\nany combination of ``__get__()``, ``__set__()`` and ``__delete__()``.\nIf it does not define ``__get__()``, then accessing the attribute will\nreturn the descriptor object itself unless there is a value in the\nobject\'s instance dictionary. If the descriptor defines ``__set__()``\nand/or ``__delete__()``, it is a data descriptor; if it defines\nneither, it is a non-data descriptor. Normally, data descriptors\ndefine both ``__get__()`` and ``__set__()``, while non-data\ndescriptors have just the ``__get__()`` method. Data descriptors with\n``__set__()`` and ``__get__()`` defined always override a redefinition\nin an instance dictionary. In contrast, non-data descriptors can be\noverridden by instances.\n\nPython methods (including ``staticmethod()`` and ``classmethod()``)\nare implemented as non-data descriptors. Accordingly, instances can\nredefine and override methods. This allows individual instances to\nacquire behaviors that differ from other instances of the same class.\n\nThe ``property()`` function is implemented as a data descriptor.\nAccordingly, instances cannot override the behavior of a property.\n\n\n__slots__\n=========\n\nBy default, instances of classes have a dictionary for attribute\nstorage. This wastes space for objects having very few instance\nvariables. The space consumption can become acute when creating large\nnumbers of instances.\n\nThe default can be overridden by defining *__slots__* in a class\ndefinition. The *__slots__* declaration takes a sequence of instance\nvariables and reserves just enough space in each instance to hold a\nvalue for each variable. Space is saved because *__dict__* is not\ncreated for each instance.\n\nobject.__slots__\n\n This class variable can be assigned a string, iterable, or sequence\n of strings with variable names used by instances. If defined in a\n class, *__slots__* reserves space for the declared variables and\n prevents the automatic creation of *__dict__* and *__weakref__* for\n each instance.\n\n\nNotes on using *__slots__*\n--------------------------\n\n* When inheriting from a class without *__slots__*, the *__dict__*\n attribute of that class will always be accessible, so a *__slots__*\n definition in the subclass is meaningless.\n\n* Without a *__dict__* variable, instances cannot be assigned new\n variables not listed in the *__slots__* definition. Attempts to\n assign to an unlisted variable name raises ``AttributeError``. If\n dynamic assignment of new variables is desired, then add\n ``\'__dict__\'`` to the sequence of strings in the *__slots__*\n declaration.\n\n* Without a *__weakref__* variable for each instance, classes defining\n *__slots__* do not support weak references to its instances. If weak\n reference support is needed, then add ``\'__weakref__\'`` to the\n sequence of strings in the *__slots__* declaration.\n\n* *__slots__* are implemented at the class level by creating\n descriptors (*Implementing Descriptors*) for each variable name. As\n a result, class attributes cannot be used to set default values for\n instance variables defined by *__slots__*; otherwise, the class\n attribute would overwrite the descriptor assignment.\n\n* The action of a *__slots__* declaration is limited to the class\n where it is defined. As a result, subclasses will have a *__dict__*\n unless they also define *__slots__* (which must only contain names\n of any *additional* slots).\n\n* If a class defines a slot also defined in a base class, the instance\n variable defined by the base class slot is inaccessible (except by\n retrieving its descriptor directly from the base class). This\n renders the meaning of the program undefined. In the future, a\n check may be added to prevent this.\n\n* Nonempty *__slots__* does not work for classes derived from\n "variable-length" built-in types such as ``int``, ``str`` and\n ``tuple``.\n\n* Any non-string iterable may be assigned to *__slots__*. Mappings may\n also be used; however, in the future, special meaning may be\n assigned to the values corresponding to each key.\n\n* *__class__* assignment works only if both classes have the same\n *__slots__*.\n', + 'attribute-access': '\nCustomizing attribute access\n****************************\n\nThe following methods can be defined to customize the meaning of\nattribute access (use of, assignment to, or deletion of ``x.name``)\nfor class instances.\n\nobject.__getattr__(self, name)\n\n Called when an attribute lookup has not found the attribute in the\n usual places (i.e. it is not an instance attribute nor is it found\n in the class tree for ``self``). ``name`` is the attribute name.\n This method should return the (computed) attribute value or raise\n an ``AttributeError`` exception.\n\n Note that if the attribute is found through the normal mechanism,\n ``__getattr__()`` is not called. (This is an intentional asymmetry\n between ``__getattr__()`` and ``__setattr__()``.) This is done both\n for efficiency reasons and because otherwise ``__getattr__()``\n would have no way to access other attributes of the instance. Note\n that at least for instance variables, you can fake total control by\n not inserting any values in the instance attribute dictionary (but\n instead inserting them in another object). See the\n ``__getattribute__()`` method below for a way to actually get total\n control over attribute access.\n\nobject.__getattribute__(self, name)\n\n Called unconditionally to implement attribute accesses for\n instances of the class. If the class also defines\n ``__getattr__()``, the latter will not be called unless\n ``__getattribute__()`` either calls it explicitly or raises an\n ``AttributeError``. This method should return the (computed)\n attribute value or raise an ``AttributeError`` exception. In order\n to avoid infinite recursion in this method, its implementation\n should always call the base class method with the same name to\n access any attributes it needs, for example,\n ``object.__getattribute__(self, name)``.\n\n Note: This method may still be bypassed when looking up special methods\n as the result of implicit invocation via language syntax or\n built-in functions. See *Special method lookup*.\n\nobject.__setattr__(self, name, value)\n\n Called when an attribute assignment is attempted. This is called\n instead of the normal mechanism (i.e. store the value in the\n instance dictionary). *name* is the attribute name, *value* is the\n value to be assigned to it.\n\n If ``__setattr__()`` wants to assign to an instance attribute, it\n should call the base class method with the same name, for example,\n ``object.__setattr__(self, name, value)``.\n\nobject.__delattr__(self, name)\n\n Like ``__setattr__()`` but for attribute deletion instead of\n assignment. This should only be implemented if ``del obj.name`` is\n meaningful for the object.\n\nobject.__dir__(self)\n\n Called when ``dir()`` is called on the object. A list must be\n returned.\n\n\nImplementing Descriptors\n========================\n\nThe following methods only apply when an instance of the class\ncontaining the method (a so-called *descriptor* class) appears in an\n*owner* class (the descriptor must be in either the owner\'s class\ndictionary or in the class dictionary for one of its parents). In the\nexamples below, "the attribute" refers to the attribute whose name is\nthe key of the property in the owner class\' ``__dict__``.\n\nobject.__get__(self, instance, owner)\n\n Called to get the attribute of the owner class (class attribute\n access) or of an instance of that class (instance attribute\n access). *owner* is always the owner class, while *instance* is the\n instance that the attribute was accessed through, or ``None`` when\n the attribute is accessed through the *owner*. This method should\n return the (computed) attribute value or raise an\n ``AttributeError`` exception.\n\nobject.__set__(self, instance, value)\n\n Called to set the attribute on an instance *instance* of the owner\n class to a new value, *value*.\n\nobject.__delete__(self, instance)\n\n Called to delete the attribute on an instance *instance* of the\n owner class.\n\n\nInvoking Descriptors\n====================\n\nIn general, a descriptor is an object attribute with "binding\nbehavior", one whose attribute access has been overridden by methods\nin the descriptor protocol: ``__get__()``, ``__set__()``, and\n``__delete__()``. If any of those methods are defined for an object,\nit is said to be a descriptor.\n\nThe default behavior for attribute access is to get, set, or delete\nthe attribute from an object\'s dictionary. For instance, ``a.x`` has a\nlookup chain starting with ``a.__dict__[\'x\']``, then\n``type(a).__dict__[\'x\']``, and continuing through the base classes of\n``type(a)`` excluding metaclasses.\n\nHowever, if the looked-up value is an object defining one of the\ndescriptor methods, then Python may override the default behavior and\ninvoke the descriptor method instead. Where this occurs in the\nprecedence chain depends on which descriptor methods were defined and\nhow they were called.\n\nThe starting point for descriptor invocation is a binding, ``a.x``.\nHow the arguments are assembled depends on ``a``:\n\nDirect Call\n The simplest and least common call is when user code directly\n invokes a descriptor method: ``x.__get__(a)``.\n\nInstance Binding\n If binding to an object instance, ``a.x`` is transformed into the\n call: ``type(a).__dict__[\'x\'].__get__(a, type(a))``.\n\nClass Binding\n If binding to a class, ``A.x`` is transformed into the call:\n ``A.__dict__[\'x\'].__get__(None, A)``.\n\nSuper Binding\n If ``a`` is an instance of ``super``, then the binding ``super(B,\n obj).m()`` searches ``obj.__class__.__mro__`` for the base class\n ``A`` immediately preceding ``B`` and then invokes the descriptor\n with the call: ``A.__dict__[\'m\'].__get__(obj, obj.__class__)``.\n\nFor instance bindings, the precedence of descriptor invocation depends\non the which descriptor methods are defined. A descriptor can define\nany combination of ``__get__()``, ``__set__()`` and ``__delete__()``.\nIf it does not define ``__get__()``, then accessing the attribute will\nreturn the descriptor object itself unless there is a value in the\nobject\'s instance dictionary. If the descriptor defines ``__set__()``\nand/or ``__delete__()``, it is a data descriptor; if it defines\nneither, it is a non-data descriptor. Normally, data descriptors\ndefine both ``__get__()`` and ``__set__()``, while non-data\ndescriptors have just the ``__get__()`` method. Data descriptors with\n``__set__()`` and ``__get__()`` defined always override a redefinition\nin an instance dictionary. In contrast, non-data descriptors can be\noverridden by instances.\n\nPython methods (including ``staticmethod()`` and ``classmethod()``)\nare implemented as non-data descriptors. Accordingly, instances can\nredefine and override methods. This allows individual instances to\nacquire behaviors that differ from other instances of the same class.\n\nThe ``property()`` function is implemented as a data descriptor.\nAccordingly, instances cannot override the behavior of a property.\n\n\n__slots__\n=========\n\nBy default, instances of classes have a dictionary for attribute\nstorage. This wastes space for objects having very few instance\nvariables. The space consumption can become acute when creating large\nnumbers of instances.\n\nThe default can be overridden by defining *__slots__* in a class\ndefinition. The *__slots__* declaration takes a sequence of instance\nvariables and reserves just enough space in each instance to hold a\nvalue for each variable. Space is saved because *__dict__* is not\ncreated for each instance.\n\nobject.__slots__\n\n This class variable can be assigned a string, iterable, or sequence\n of strings with variable names used by instances. If defined in a\n class, *__slots__* reserves space for the declared variables and\n prevents the automatic creation of *__dict__* and *__weakref__* for\n each instance.\n\n\nNotes on using *__slots__*\n--------------------------\n\n* When inheriting from a class without *__slots__*, the *__dict__*\n attribute of that class will always be accessible, so a *__slots__*\n definition in the subclass is meaningless.\n\n* Without a *__dict__* variable, instances cannot be assigned new\n variables not listed in the *__slots__* definition. Attempts to\n assign to an unlisted variable name raises ``AttributeError``. If\n dynamic assignment of new variables is desired, then add\n ``\'__dict__\'`` to the sequence of strings in the *__slots__*\n declaration.\n\n* Without a *__weakref__* variable for each instance, classes defining\n *__slots__* do not support weak references to its instances. If weak\n reference support is needed, then add ``\'__weakref__\'`` to the\n sequence of strings in the *__slots__* declaration.\n\n* *__slots__* are implemented at the class level by creating\n descriptors (*Implementing Descriptors*) for each variable name. As\n a result, class attributes cannot be used to set default values for\n instance variables defined by *__slots__*; otherwise, the class\n attribute would overwrite the descriptor assignment.\n\n* The action of a *__slots__* declaration is limited to the class\n where it is defined. As a result, subclasses will have a *__dict__*\n unless they also define *__slots__* (which must only contain names\n of any *additional* slots).\n\n* If a class defines a slot also defined in a base class, the instance\n variable defined by the base class slot is inaccessible (except by\n retrieving its descriptor directly from the base class). This\n renders the meaning of the program undefined. In the future, a\n check may be added to prevent this.\n\n* Nonempty *__slots__* does not work for classes derived from\n "variable-length" built-in types such as ``int``, ``str`` and\n ``tuple``.\n\n* Any non-string iterable may be assigned to *__slots__*. Mappings may\n also be used; however, in the future, special meaning may be\n assigned to the values corresponding to each key.\n\n* *__class__* assignment works only if both classes have the same\n *__slots__*.\n', 'attribute-references': '\nAttribute references\n********************\n\nAn attribute reference is a primary followed by a period and a name:\n\n attributeref ::= primary "." identifier\n\nThe primary must evaluate to an object of a type that supports\nattribute references, which most objects do. This object is then\nasked to produce the attribute whose name is the identifier (which can\nbe customized by overriding the ``__getattr__()`` method). If this\nattribute is not available, the exception ``AttributeError`` is\nraised. Otherwise, the type and value of the object produced is\ndetermined by the object. Multiple evaluations of the same attribute\nreference may yield different objects.\n', 'augassign': '\nAugmented assignment statements\n*******************************\n\nAugmented assignment is the combination, in a single statement, of a\nbinary operation and an assignment statement:\n\n augmented_assignment_stmt ::= augtarget augop (expression_list | yield_expression)\n augtarget ::= identifier | attributeref | subscription | slicing\n augop ::= "+=" | "-=" | "*=" | "/=" | "//=" | "%=" | "**="\n | ">>=" | "<<=" | "&=" | "^=" | "|="\n\n(See section *Primaries* for the syntax definitions for the last three\nsymbols.)\n\nAn augmented assignment evaluates the target (which, unlike normal\nassignment statements, cannot be an unpacking) and the expression\nlist, performs the binary operation specific to the type of assignment\non the two operands, and assigns the result to the original target.\nThe target is only evaluated once.\n\nAn augmented assignment expression like ``x += 1`` can be rewritten as\n``x = x + 1`` to achieve a similar, but not exactly equal effect. In\nthe augmented version, ``x`` is only evaluated once. Also, when\npossible, the actual operation is performed *in-place*, meaning that\nrather than creating a new object and assigning that to the target,\nthe old object is modified instead.\n\nWith the exception of assigning to tuples and multiple targets in a\nsingle statement, the assignment done by augmented assignment\nstatements is handled the same way as normal assignments. Similarly,\nwith the exception of the possible *in-place* behavior, the binary\noperation performed by augmented assignment is the same as the normal\nbinary operations.\n\nFor targets which are attribute references, the same *caveat about\nclass and instance attributes* applies as for regular assignments.\n', 'binary': '\nBinary arithmetic operations\n****************************\n\nThe binary arithmetic operations have the conventional priority\nlevels. Note that some of these operations also apply to certain non-\nnumeric types. Apart from the power operator, there are only two\nlevels, one for multiplicative operators and one for additive\noperators:\n\n m_expr ::= u_expr | m_expr "*" u_expr | m_expr "//" u_expr | m_expr "/" u_expr\n | m_expr "%" u_expr\n a_expr ::= m_expr | a_expr "+" m_expr | a_expr "-" m_expr\n\nThe ``*`` (multiplication) operator yields the product of its\narguments. The arguments must either both be numbers, or one argument\nmust be an integer and the other must be a sequence. In the former\ncase, the numbers are converted to a common type and then multiplied\ntogether. In the latter case, sequence repetition is performed; a\nnegative repetition factor yields an empty sequence.\n\nThe ``/`` (division) and ``//`` (floor division) operators yield the\nquotient of their arguments. The numeric arguments are first\nconverted to a common type. Integer division yields a float, while\nfloor division of integers results in an integer; the result is that\nof mathematical division with the \'floor\' function applied to the\nresult. Division by zero raises the ``ZeroDivisionError`` exception.\n\nThe ``%`` (modulo) operator yields the remainder from the division of\nthe first argument by the second. The numeric arguments are first\nconverted to a common type. A zero right argument raises the\n``ZeroDivisionError`` exception. The arguments may be floating point\nnumbers, e.g., ``3.14%0.7`` equals ``0.34`` (since ``3.14`` equals\n``4*0.7 + 0.34``.) The modulo operator always yields a result with\nthe same sign as its second operand (or zero); the absolute value of\nthe result is strictly smaller than the absolute value of the second\noperand [1].\n\nThe floor division and modulo operators are connected by the following\nidentity: ``x == (x//y)*y + (x%y)``. Floor division and modulo are\nalso connected with the built-in function ``divmod()``: ``divmod(x, y)\n== (x//y, x%y)``. [2].\n\nIn addition to performing the modulo operation on numbers, the ``%``\noperator is also overloaded by string objects to perform old-style\nstring formatting (also known as interpolation). The syntax for\nstring formatting is described in the Python Library Reference,\nsection *Old String Formatting Operations*.\n\nThe floor division operator, the modulo operator, and the ``divmod()``\nfunction are not defined for complex numbers. Instead, convert to a\nfloating point number using the ``abs()`` function if appropriate.\n\nThe ``+`` (addition) operator yields the sum of its arguments. The\narguments must either both be numbers or both sequences of the same\ntype. In the former case, the numbers are converted to a common type\nand then added together. In the latter case, the sequences are\nconcatenated.\n\nThe ``-`` (subtraction) operator yields the difference of its\narguments. The numeric arguments are first converted to a common\ntype.\n', @@ -16,9 +16,9 @@ 'break': '\nThe ``break`` statement\n***********************\n\n break_stmt ::= "break"\n\n``break`` may only occur syntactically nested in a ``for`` or\n``while`` loop, but not nested in a function or class definition\nwithin that loop.\n\nIt terminates the nearest enclosing loop, skipping the optional\n``else`` clause if the loop has one.\n\nIf a ``for`` loop is terminated by ``break``, the loop control target\nkeeps its current value.\n\nWhen ``break`` passes control out of a ``try`` statement with a\n``finally`` clause, that ``finally`` clause is executed before really\nleaving the loop.\n', 'callable-types': '\nEmulating callable objects\n**************************\n\nobject.__call__(self[, args...])\n\n Called when the instance is "called" as a function; if this method\n is defined, ``x(arg1, arg2, ...)`` is a shorthand for\n ``x.__call__(arg1, arg2, ...)``.\n', 'calls': '\nCalls\n*****\n\nA call calls a callable object (e.g., a function) with a possibly\nempty series of arguments:\n\n call ::= primary "(" [argument_list [","] | comprehension] ")"\n argument_list ::= positional_arguments ["," keyword_arguments]\n ["," "*" expression] ["," keyword_arguments]\n ["," "**" expression]\n | keyword_arguments ["," "*" expression]\n ["," keyword_arguments] ["," "**" expression]\n | "*" expression ["," keyword_arguments] ["," "**" expression]\n | "**" expression\n positional_arguments ::= expression ("," expression)*\n keyword_arguments ::= keyword_item ("," keyword_item)*\n keyword_item ::= identifier "=" expression\n\nA trailing comma may be present after the positional and keyword\narguments but does not affect the semantics.\n\nThe primary must evaluate to a callable object (user-defined\nfunctions, built-in functions, methods of built-in objects, class\nobjects, methods of class instances, and all objects having a\n``__call__()`` method are callable). All argument expressions are\nevaluated before the call is attempted. Please refer to section\n*Function definitions* for the syntax of formal parameter lists.\n\nIf keyword arguments are present, they are first converted to\npositional arguments, as follows. First, a list of unfilled slots is\ncreated for the formal parameters. If there are N positional\narguments, they are placed in the first N slots. Next, for each\nkeyword argument, the identifier is used to determine the\ncorresponding slot (if the identifier is the same as the first formal\nparameter name, the first slot is used, and so on). If the slot is\nalready filled, a ``TypeError`` exception is raised. Otherwise, the\nvalue of the argument is placed in the slot, filling it (even if the\nexpression is ``None``, it fills the slot). When all arguments have\nbeen processed, the slots that are still unfilled are filled with the\ncorresponding default value from the function definition. (Default\nvalues are calculated, once, when the function is defined; thus, a\nmutable object such as a list or dictionary used as default value will\nbe shared by all calls that don\'t specify an argument value for the\ncorresponding slot; this should usually be avoided.) If there are any\nunfilled slots for which no default value is specified, a\n``TypeError`` exception is raised. Otherwise, the list of filled\nslots is used as the argument list for the call.\n\n**CPython implementation detail:** An implementation may provide\nbuilt-in functions whose positional parameters do not have names, even\nif they are \'named\' for the purpose of documentation, and which\ntherefore cannot be supplied by keyword. In CPython, this is the case\nfor functions implemented in C that use ``PyArg_ParseTuple()`` to\nparse their arguments.\n\nIf there are more positional arguments than there are formal parameter\nslots, a ``TypeError`` exception is raised, unless a formal parameter\nusing the syntax ``*identifier`` is present; in this case, that formal\nparameter receives a tuple containing the excess positional arguments\n(or an empty tuple if there were no excess positional arguments).\n\nIf any keyword argument does not correspond to a formal parameter\nname, a ``TypeError`` exception is raised, unless a formal parameter\nusing the syntax ``**identifier`` is present; in this case, that\nformal parameter receives a dictionary containing the excess keyword\narguments (using the keywords as keys and the argument values as\ncorresponding values), or a (new) empty dictionary if there were no\nexcess keyword arguments.\n\nIf the syntax ``*expression`` appears in the function call,\n``expression`` must evaluate to a sequence. Elements from this\nsequence are treated as if they were additional positional arguments;\nif there are positional arguments *x1*,..., *xN*, and ``expression``\nevaluates to a sequence *y1*, ..., *yM*, this is equivalent to a call\nwith M+N positional arguments *x1*, ..., *xN*, *y1*, ..., *yM*.\n\nA consequence of this is that although the ``*expression`` syntax may\nappear *after* some keyword arguments, it is processed *before* the\nkeyword arguments (and the ``**expression`` argument, if any -- see\nbelow). So:\n\n >>> def f(a, b):\n ... print(a, b)\n ...\n >>> f(b=1, *(2,))\n 2 1\n >>> f(a=1, *(2,))\n Traceback (most recent call last):\n File "", line 1, in ?\n TypeError: f() got multiple values for keyword argument \'a\'\n >>> f(1, *(2,))\n 1 2\n\nIt is unusual for both keyword arguments and the ``*expression``\nsyntax to be used in the same call, so in practice this confusion does\nnot arise.\n\nIf the syntax ``**expression`` appears in the function call,\n``expression`` must evaluate to a mapping, the contents of which are\ntreated as additional keyword arguments. In the case of a keyword\nappearing in both ``expression`` and as an explicit keyword argument,\na ``TypeError`` exception is raised.\n\nFormal parameters using the syntax ``*identifier`` or ``**identifier``\ncannot be used as positional argument slots or as keyword argument\nnames.\n\nA call always returns some value, possibly ``None``, unless it raises\nan exception. How this value is computed depends on the type of the\ncallable object.\n\nIf it is---\n\na user-defined function:\n The code block for the function is executed, passing it the\n argument list. The first thing the code block will do is bind the\n formal parameters to the arguments; this is described in section\n *Function definitions*. When the code block executes a ``return``\n statement, this specifies the return value of the function call.\n\na built-in function or method:\n The result is up to the interpreter; see *Built-in Functions* for\n the descriptions of built-in functions and methods.\n\na class object:\n A new instance of that class is returned.\n\na class instance method:\n The corresponding user-defined function is called, with an argument\n list that is one longer than the argument list of the call: the\n instance becomes the first argument.\n\na class instance:\n The class must define a ``__call__()`` method; the effect is then\n the same as if that method was called.\n', - 'class': '\nClass definitions\n*****************\n\nA class definition defines a class object (see section *The standard\ntype hierarchy*):\n\n classdef ::= [decorators] "class" classname [inheritance] ":" suite\n inheritance ::= "(" [argument_list [","] | comprehension] ")"\n classname ::= identifier\n\nA class definition is an executable statement. The inheritance list\nusually gives a list of base classes (see *Customizing class creation*\nfor more advanced uses), so each item in the list should evaluate to a\nclass object which allows subclassing. Classes without an inheritance\nlist inherit, by default, from the base class ``object``; hence,\n\n class Foo:\n pass\n\nis equivalent to\n\n class Foo(object):\n pass\n\nThe class\'s suite is then executed in a new execution frame (see\n*Naming and binding*), using a newly created local namespace and the\noriginal global namespace. (Usually, the suite contains mostly\nfunction definitions.) When the class\'s suite finishes execution, its\nexecution frame is discarded but its local namespace is saved. [4] A\nclass object is then created using the inheritance list for the base\nclasses and the saved local namespace for the attribute dictionary.\nThe class name is bound to this class object in the original local\nnamespace.\n\nClass creation can be customized heavily using *metaclasses*.\n\nClasses can also be decorated: just like when decorating functions,\n\n @f1(arg)\n @f2\n class Foo: pass\n\nis equivalent to\n\n class Foo: pass\n Foo = f1(arg)(f2(Foo))\n\nThe evaluation rules for the decorator expressions are the same as for\nfunction decorators. The result must be a class object, which is then\nbound to the class name.\n\n**Programmer\'s note:** Variables defined in the class definition are\nclass attributes; they are shared by instances. Instance attributes\ncan be set in a method with ``self.name = value``. Both class and\ninstance attributes are accessible through the notation\n"``self.name``", and an instance attribute hides a class attribute\nwith the same name when accessed in this way. Class attributes can be\nused as defaults for instance attributes, but using mutable values\nthere can lead to unexpected results. *Descriptors* can be used to\ncreate instance variables with different implementation details.\n\nSee also:\n\n **PEP 3116** - Metaclasses in Python 3 **PEP 3129** - Class\n Decorators\n\n-[ Footnotes ]-\n\n[1] The exception is propagated to the invocation stack only if there\n is no ``finally`` clause that negates the exception.\n\n[2] Currently, control "flows off the end" except in the case of an\n exception or the execution of a ``return``, ``continue``, or\n ``break`` statement.\n\n[3] A string literal appearing as the first statement in the function\n body is transformed into the function\'s ``__doc__`` attribute and\n therefore the function\'s *docstring*.\n\n[4] A string literal appearing as the first statement in the class\n body is transformed into the namespace\'s ``__doc__`` item and\n therefore the class\'s *docstring*.\n', + 'class': '\nClass definitions\n*****************\n\nA class definition defines a class object (see section *The standard\ntype hierarchy*):\n\n classdef ::= [decorators] "class" classname [inheritance] ":" suite\n inheritance ::= "(" [argument_list [","] | comprehension] ")"\n classname ::= identifier\n\nA class definition is an executable statement. The inheritance list\nusually gives a list of base classes (see *Customizing class creation*\nfor more advanced uses), so each item in the list should evaluate to a\nclass object which allows subclassing. Classes without an inheritance\nlist inherit, by default, from the base class ``object``; hence,\n\n class Foo:\n pass\n\nis equivalent to\n\n class Foo(object):\n pass\n\nThe class\'s suite is then executed in a new execution frame (see\n*Naming and binding*), using a newly created local namespace and the\noriginal global namespace. (Usually, the suite contains mostly\nfunction definitions.) When the class\'s suite finishes execution, its\nexecution frame is discarded but its local namespace is saved. [4] A\nclass object is then created using the inheritance list for the base\nclasses and the saved local namespace for the attribute dictionary.\nThe class name is bound to this class object in the original local\nnamespace.\n\nClass creation can be customized heavily using *metaclasses*.\n\nClasses can also be decorated: just like when decorating functions,\n\n @f1(arg)\n @f2\n class Foo: pass\n\nis equivalent to\n\n class Foo: pass\n Foo = f1(arg)(f2(Foo))\n\nThe evaluation rules for the decorator expressions are the same as for\nfunction decorators. The result must be a class object, which is then\nbound to the class name.\n\n**Programmer\'s note:** Variables defined in the class definition are\nclass attributes; they are shared by instances. Instance attributes\ncan be set in a method with ``self.name = value``. Both class and\ninstance attributes are accessible through the notation\n"``self.name``", and an instance attribute hides a class attribute\nwith the same name when accessed in this way. Class attributes can be\nused as defaults for instance attributes, but using mutable values\nthere can lead to unexpected results. *Descriptors* can be used to\ncreate instance variables with different implementation details.\n\nSee also:\n\n **PEP 3115** - Metaclasses in Python 3 **PEP 3129** - Class\n Decorators\n\n-[ Footnotes ]-\n\n[1] The exception is propagated to the invocation stack only if there\n is no ``finally`` clause that negates the exception.\n\n[2] Currently, control "flows off the end" except in the case of an\n exception or the execution of a ``return``, ``continue``, or\n ``break`` statement.\n\n[3] A string literal appearing as the first statement in the function\n body is transformed into the function\'s ``__doc__`` attribute and\n therefore the function\'s *docstring*.\n\n[4] A string literal appearing as the first statement in the class\n body is transformed into the namespace\'s ``__doc__`` item and\n therefore the class\'s *docstring*.\n', 'comparisons': '\nComparisons\n***********\n\nUnlike C, all comparison operations in Python have the same priority,\nwhich is lower than that of any arithmetic, shifting or bitwise\noperation. Also unlike C, expressions like ``a < b < c`` have the\ninterpretation that is conventional in mathematics:\n\n comparison ::= or_expr ( comp_operator or_expr )*\n comp_operator ::= "<" | ">" | "==" | ">=" | "<=" | "!="\n | "is" ["not"] | ["not"] "in"\n\nComparisons yield boolean values: ``True`` or ``False``.\n\nComparisons can be chained arbitrarily, e.g., ``x < y <= z`` is\nequivalent to ``x < y and y <= z``, except that ``y`` is evaluated\nonly once (but in both cases ``z`` is not evaluated at all when ``x <\ny`` is found to be false).\n\nFormally, if *a*, *b*, *c*, ..., *y*, *z* are expressions and *op1*,\n*op2*, ..., *opN* are comparison operators, then ``a op1 b op2 c ... y\nopN z`` is equivalent to ``a op1 b and b op2 c and ... y opN z``,\nexcept that each expression is evaluated at most once.\n\nNote that ``a op1 b op2 c`` doesn\'t imply any kind of comparison\nbetween *a* and *c*, so that, e.g., ``x < y > z`` is perfectly legal\n(though perhaps not pretty).\n\nThe operators ``<``, ``>``, ``==``, ``>=``, ``<=``, and ``!=`` compare\nthe values of two objects. The objects need not have the same type.\nIf both are numbers, they are converted to a common type. Otherwise,\nthe ``==`` and ``!=`` operators *always* consider objects of different\ntypes to be unequal, while the ``<``, ``>``, ``>=`` and ``<=``\noperators raise a ``TypeError`` when comparing objects of different\ntypes that do not implement these operators for the given pair of\ntypes. You can control comparison behavior of objects of non-built-in\ntypes by defining rich comparison methods like ``__gt__()``, described\nin section *Basic customization*.\n\nComparison of objects of the same type depends on the type:\n\n* Numbers are compared arithmetically.\n\n* The values ``float(\'NaN\')`` and ``Decimal(\'NaN\')`` are special. The\n are identical to themselves, ``x is x`` but are not equal to\n themselves, ``x != x``. Additionally, comparing any value to a\n not-a-number value will return ``False``. For example, both ``3 <\n float(\'NaN\')`` and ``float(\'NaN\') < 3`` will return ``False``.\n\n* Bytes objects are compared lexicographically using the numeric\n values of their elements.\n\n* Strings are compared lexicographically using the numeric equivalents\n (the result of the built-in function ``ord()``) of their characters.\n [3] String and bytes object can\'t be compared!\n\n* Tuples and lists are compared lexicographically using comparison of\n corresponding elements. This means that to compare equal, each\n element must compare equal and the two sequences must be of the same\n type and have the same length.\n\n If not equal, the sequences are ordered the same as their first\n differing elements. For example, ``[1,2,x] <= [1,2,y]`` has the\n same value as ``x <= y``. If the corresponding element does not\n exist, the shorter sequence is ordered first (for example, ``[1,2] <\n [1,2,3]``).\n\n* Mappings (dictionaries) compare equal if and only if they have the\n same ``(key, value)`` pairs. Order comparisons ``(\'<\', \'<=\', \'>=\',\n \'>\')`` raise ``TypeError``.\n\n* Sets and frozensets define comparison operators to mean subset and\n superset tests. Those relations do not define total orderings (the\n two sets ``{1,2}`` and {2,3} are not equal, nor subsets of one\n another, nor supersets of one another). Accordingly, sets are not\n appropriate arguments for functions which depend on total ordering.\n For example, ``min()``, ``max()``, and ``sorted()`` produce\n undefined results given a list of sets as inputs.\n\n* Most other objects of built-in types compare unequal unless they are\n the same object; the choice whether one object is considered smaller\n or larger than another one is made arbitrarily but consistently\n within one execution of a program.\n\nComparison of objects of the differing types depends on whether either\nof the types provide explicit support for the comparison. Most\nnumeric types can be compared with one another, but comparisons of\n``float`` and ``Decimal`` are not supported to avoid the inevitable\nconfusion arising from representation issues such as ``float(\'1.1\')``\nbeing inexactly represented and therefore not exactly equal to\n``Decimal(\'1.1\')`` which is. When cross-type comparison is not\nsupported, the comparison method returns ``NotImplemented``. This can\ncreate the illusion of non-transitivity between supported cross-type\ncomparisons and unsupported comparisons. For example, ``Decimal(2) ==\n2`` and ``2 == float(2)`` but ``Decimal(2) != float(2)``.\n\nThe operators ``in`` and ``not in`` test for membership. ``x in s``\nevaluates to true if *x* is a member of *s*, and false otherwise. ``x\nnot in s`` returns the negation of ``x in s``. All built-in sequences\nand set types support this as well as dictionary, for which ``in``\ntests whether a the dictionary has a given key. For container types\nsuch as list, tuple, set, frozenset, dict, or collections.deque, the\nexpression ``x in y`` is equivalent to ``any(x is e or x == e for e in\ny)``.\n\nFor the string and bytes types, ``x in y`` is true if and only if *x*\nis a substring of *y*. An equivalent test is ``y.find(x) != -1``.\nEmpty strings are always considered to be a substring of any other\nstring, so ``"" in "abc"`` will return ``True``.\n\nFor user-defined classes which define the ``__contains__()`` method,\n``x in y`` is true if and only if ``y.__contains__(x)`` is true.\n\nFor user-defined classes which do not define ``__contains__()`` but do\ndefine ``__iter__()``, ``x in y`` is true if some value ``z`` with ``x\n== z`` is produced while iterating over ``y``. If an exception is\nraised during the iteration, it is as if ``in`` raised that exception.\n\nLastly, the old-style iteration protocol is tried: if a class defines\n``__getitem__()``, ``x in y`` is true if and only if there is a non-\nnegative integer index *i* such that ``x == y[i]``, and all lower\ninteger indices do not raise ``IndexError`` exception. (If any other\nexception is raised, it is as if ``in`` raised that exception).\n\nThe operator ``not in`` is defined to have the inverse true value of\n``in``.\n\nThe operators ``is`` and ``is not`` test for object identity: ``x is\ny`` is true if and only if *x* and *y* are the same object. ``x is\nnot y`` yields the inverse truth value. [4]\n', - 'compound': '\nCompound statements\n*******************\n\nCompound statements contain (groups of) other statements; they affect\nor control the execution of those other statements in some way. In\ngeneral, compound statements span multiple lines, although in simple\nincarnations a whole compound statement may be contained in one line.\n\nThe ``if``, ``while`` and ``for`` statements implement traditional\ncontrol flow constructs. ``try`` specifies exception handlers and/or\ncleanup code for a group of statements, while the ``with`` statement\nallows the execution of initialization and finalization code around a\nblock of code. Function and class definitions are also syntactically\ncompound statements.\n\nCompound statements consist of one or more \'clauses.\' A clause\nconsists of a header and a \'suite.\' The clause headers of a\nparticular compound statement are all at the same indentation level.\nEach clause header begins with a uniquely identifying keyword and ends\nwith a colon. A suite is a group of statements controlled by a\nclause. A suite can be one or more semicolon-separated simple\nstatements on the same line as the header, following the header\'s\ncolon, or it can be one or more indented statements on subsequent\nlines. Only the latter form of suite can contain nested compound\nstatements; the following is illegal, mostly because it wouldn\'t be\nclear to which ``if`` clause a following ``else`` clause would belong:\n\n if test1: if test2: print(x)\n\nAlso note that the semicolon binds tighter than the colon in this\ncontext, so that in the following example, either all or none of the\n``print()`` calls are executed:\n\n if x < y < z: print(x); print(y); print(z)\n\nSummarizing:\n\n compound_stmt ::= if_stmt\n | while_stmt\n | for_stmt\n | try_stmt\n | with_stmt\n | funcdef\n | classdef\n suite ::= stmt_list NEWLINE | NEWLINE INDENT statement+ DEDENT\n statement ::= stmt_list NEWLINE | compound_stmt\n stmt_list ::= simple_stmt (";" simple_stmt)* [";"]\n\nNote that statements always end in a ``NEWLINE`` possibly followed by\na ``DEDENT``. Also note that optional continuation clauses always\nbegin with a keyword that cannot start a statement, thus there are no\nambiguities (the \'dangling ``else``\' problem is solved in Python by\nrequiring nested ``if`` statements to be indented).\n\nThe formatting of the grammar rules in the following sections places\neach clause on a separate line for clarity.\n\n\nThe ``if`` statement\n====================\n\nThe ``if`` statement is used for conditional execution:\n\n if_stmt ::= "if" expression ":" suite\n ( "elif" expression ":" suite )*\n ["else" ":" suite]\n\nIt selects exactly one of the suites by evaluating the expressions one\nby one until one is found to be true (see section *Boolean operations*\nfor the definition of true and false); then that suite is executed\n(and no other part of the ``if`` statement is executed or evaluated).\nIf all expressions are false, the suite of the ``else`` clause, if\npresent, is executed.\n\n\nThe ``while`` statement\n=======================\n\nThe ``while`` statement is used for repeated execution as long as an\nexpression is true:\n\n while_stmt ::= "while" expression ":" suite\n ["else" ":" suite]\n\nThis repeatedly tests the expression and, if it is true, executes the\nfirst suite; if the expression is false (which may be the first time\nit is tested) the suite of the ``else`` clause, if present, is\nexecuted and the loop terminates.\n\nA ``break`` statement executed in the first suite terminates the loop\nwithout executing the ``else`` clause\'s suite. A ``continue``\nstatement executed in the first suite skips the rest of the suite and\ngoes back to testing the expression.\n\n\nThe ``for`` statement\n=====================\n\nThe ``for`` statement is used to iterate over the elements of a\nsequence (such as a string, tuple or list) or other iterable object:\n\n for_stmt ::= "for" target_list "in" expression_list ":" suite\n ["else" ":" suite]\n\nThe expression list is evaluated once; it should yield an iterable\nobject. An iterator is created for the result of the\n``expression_list``. The suite is then executed once for each item\nprovided by the iterator, in the order of ascending indices. Each\nitem in turn is assigned to the target list using the standard rules\nfor assignments (see *Assignment statements*), and then the suite is\nexecuted. When the items are exhausted (which is immediately when the\nsequence is empty or an iterator raises a ``StopIteration``\nexception), the suite in the ``else`` clause, if present, is executed,\nand the loop terminates.\n\nA ``break`` statement executed in the first suite terminates the loop\nwithout executing the ``else`` clause\'s suite. A ``continue``\nstatement executed in the first suite skips the rest of the suite and\ncontinues with the next item, or with the ``else`` clause if there was\nno next item.\n\nThe suite may assign to the variable(s) in the target list; this does\nnot affect the next item assigned to it.\n\nNames in the target list are not deleted when the loop is finished,\nbut if the sequence is empty, it will not have been assigned to at all\nby the loop. Hint: the built-in function ``range()`` returns an\niterator of integers suitable to emulate the effect of Pascal\'s ``for\ni := a to b do``; e.g., ``list(range(3))`` returns the list ``[0, 1,\n2]``.\n\nNote: There is a subtlety when the sequence is being modified by the loop\n (this can only occur for mutable sequences, i.e. lists). An\n internal counter is used to keep track of which item is used next,\n and this is incremented on each iteration. When this counter has\n reached the length of the sequence the loop terminates. This means\n that if the suite deletes the current (or a previous) item from the\n sequence, the next item will be skipped (since it gets the index of\n the current item which has already been treated). Likewise, if the\n suite inserts an item in the sequence before the current item, the\n current item will be treated again the next time through the loop.\n This can lead to nasty bugs that can be avoided by making a\n temporary copy using a slice of the whole sequence, e.g.,\n\n for x in a[:]:\n if x < 0: a.remove(x)\n\n\nThe ``try`` statement\n=====================\n\nThe ``try`` statement specifies exception handlers and/or cleanup code\nfor a group of statements:\n\n try_stmt ::= try1_stmt | try2_stmt\n try1_stmt ::= "try" ":" suite\n ("except" [expression ["as" target]] ":" suite)+\n ["else" ":" suite]\n ["finally" ":" suite]\n try2_stmt ::= "try" ":" suite\n "finally" ":" suite\n\nThe ``except`` clause(s) specify one or more exception handlers. When\nno exception occurs in the ``try`` clause, no exception handler is\nexecuted. When an exception occurs in the ``try`` suite, a search for\nan exception handler is started. This search inspects the except\nclauses in turn until one is found that matches the exception. An\nexpression-less except clause, if present, must be last; it matches\nany exception. For an except clause with an expression, that\nexpression is evaluated, and the clause matches the exception if the\nresulting object is "compatible" with the exception. An object is\ncompatible with an exception if it is the class or a base class of the\nexception object or a tuple containing an item compatible with the\nexception.\n\nIf no except clause matches the exception, the search for an exception\nhandler continues in the surrounding code and on the invocation stack.\n[1]\n\nIf the evaluation of an expression in the header of an except clause\nraises an exception, the original search for a handler is canceled and\na search starts for the new exception in the surrounding code and on\nthe call stack (it is treated as if the entire ``try`` statement\nraised the exception).\n\nWhen a matching except clause is found, the exception is assigned to\nthe target specified after the ``as`` keyword in that except clause,\nif present, and the except clause\'s suite is executed. All except\nclauses must have an executable block. When the end of this block is\nreached, execution continues normally after the entire try statement.\n(This means that if two nested handlers exist for the same exception,\nand the exception occurs in the try clause of the inner handler, the\nouter handler will not handle the exception.)\n\nWhen an exception has been assigned using ``as target``, it is cleared\nat the end of the except clause. This is as if\n\n except E as N:\n foo\n\nwas translated to\n\n except E as N:\n try:\n foo\n finally:\n del N\n\nThis means the exception must be assigned to a different name to be\nable to refer to it after the except clause. Exceptions are cleared\nbecause with the traceback attached to them, they form a reference\ncycle with the stack frame, keeping all locals in that frame alive\nuntil the next garbage collection occurs.\n\nBefore an except clause\'s suite is executed, details about the\nexception are stored in the ``sys`` module and can be access via\n``sys.exc_info()``. ``sys.exc_info()`` returns a 3-tuple consisting of\nthe exception class, the exception instance and a traceback object\n(see section *The standard type hierarchy*) identifying the point in\nthe program where the exception occurred. ``sys.exc_info()`` values\nare restored to their previous values (before the call) when returning\nfrom a function that handled an exception.\n\nThe optional ``else`` clause is executed if and when control flows off\nthe end of the ``try`` clause. [2] Exceptions in the ``else`` clause\nare not handled by the preceding ``except`` clauses.\n\nIf ``finally`` is present, it specifies a \'cleanup\' handler. The\n``try`` clause is executed, including any ``except`` and ``else``\nclauses. If an exception occurs in any of the clauses and is not\nhandled, the exception is temporarily saved. The ``finally`` clause is\nexecuted. If there is a saved exception, it is re-raised at the end\nof the ``finally`` clause. If the ``finally`` clause raises another\nexception or executes a ``return`` or ``break`` statement, the saved\nexception is lost. The exception information is not available to the\nprogram during execution of the ``finally`` clause.\n\nWhen a ``return``, ``break`` or ``continue`` statement is executed in\nthe ``try`` suite of a ``try``...``finally`` statement, the\n``finally`` clause is also executed \'on the way out.\' A ``continue``\nstatement is illegal in the ``finally`` clause. (The reason is a\nproblem with the current implementation --- this restriction may be\nlifted in the future).\n\nAdditional information on exceptions can be found in section\n*Exceptions*, and information on using the ``raise`` statement to\ngenerate exceptions may be found in section *The raise statement*.\n\n\nThe ``with`` statement\n======================\n\nThe ``with`` statement is used to wrap the execution of a block with\nmethods defined by a context manager (see section *With Statement\nContext Managers*). This allows common\n``try``...``except``...``finally`` usage patterns to be encapsulated\nfor convenient reuse.\n\n with_stmt ::= "with" with_item ("," with_item)* ":" suite\n with_item ::= expression ["as" target]\n\nThe execution of the ``with`` statement with one "item" proceeds as\nfollows:\n\n1. The context expression (the expression given in the ``with_item``)\n is evaluated to obtain a context manager.\n\n2. The context manager\'s ``__exit__()`` is loaded for later use.\n\n3. The context manager\'s ``__enter__()`` method is invoked.\n\n4. If a target was included in the ``with`` statement, the return\n value from ``__enter__()`` is assigned to it.\n\n Note: The ``with`` statement guarantees that if the ``__enter__()``\n method returns without an error, then ``__exit__()`` will always\n be called. Thus, if an error occurs during the assignment to the\n target list, it will be treated the same as an error occurring\n within the suite would be. See step 6 below.\n\n5. The suite is executed.\n\n6. The context manager\'s ``__exit__()`` method is invoked. If an\n exception caused the suite to be exited, its type, value, and\n traceback are passed as arguments to ``__exit__()``. Otherwise,\n three ``None`` arguments are supplied.\n\n If the suite was exited due to an exception, and the return value\n from the ``__exit__()`` method was false, the exception is\n reraised. If the return value was true, the exception is\n suppressed, and execution continues with the statement following\n the ``with`` statement.\n\n If the suite was exited for any reason other than an exception, the\n return value from ``__exit__()`` is ignored, and execution proceeds\n at the normal location for the kind of exit that was taken.\n\nWith more than one item, the context managers are processed as if\nmultiple ``with`` statements were nested:\n\n with A() as a, B() as b:\n suite\n\nis equivalent to\n\n with A() as a:\n with B() as b:\n suite\n\nChanged in version 3.1: Support for multiple context expressions.\n\nSee also:\n\n **PEP 0343** - The "with" statement\n The specification, background, and examples for the Python\n ``with`` statement.\n\n\nFunction definitions\n====================\n\nA function definition defines a user-defined function object (see\nsection *The standard type hierarchy*):\n\n funcdef ::= [decorators] "def" funcname "(" [parameter_list] ")" ["->" expression] ":" suite\n decorators ::= decorator+\n decorator ::= "@" dotted_name ["(" [argument_list [","]] ")"] NEWLINE\n dotted_name ::= identifier ("." identifier)*\n parameter_list ::= (defparameter ",")*\n ( "*" [parameter] ("," defparameter)*\n [, "**" parameter]\n | "**" parameter\n | defparameter [","] )\n parameter ::= identifier [":" expression]\n defparameter ::= parameter ["=" expression]\n funcname ::= identifier\n\nA function definition is an executable statement. Its execution binds\nthe function name in the current local namespace to a function object\n(a wrapper around the executable code for the function). This\nfunction object contains a reference to the current global namespace\nas the global namespace to be used when the function is called.\n\nThe function definition does not execute the function body; this gets\nexecuted only when the function is called. [3]\n\nA function definition may be wrapped by one or more *decorator*\nexpressions. Decorator expressions are evaluated when the function is\ndefined, in the scope that contains the function definition. The\nresult must be a callable, which is invoked with the function object\nas the only argument. The returned value is bound to the function name\ninstead of the function object. Multiple decorators are applied in\nnested fashion. For example, the following code\n\n @f1(arg)\n @f2\n def func(): pass\n\nis equivalent to\n\n def func(): pass\n func = f1(arg)(f2(func))\n\nWhen one or more parameters have the form *parameter* ``=``\n*expression*, the function is said to have "default parameter values."\nFor a parameter with a default value, the corresponding argument may\nbe omitted from a call, in which case the parameter\'s default value is\nsubstituted. If a parameter has a default value, all following\nparameters up until the "``*``" must also have a default value ---\nthis is a syntactic restriction that is not expressed by the grammar.\n\n**Default parameter values are evaluated when the function definition\nis executed.** This means that the expression is evaluated once, when\nthe function is defined, and that that same "pre-computed" value is\nused for each call. This is especially important to understand when a\ndefault parameter is a mutable object, such as a list or a dictionary:\nif the function modifies the object (e.g. by appending an item to a\nlist), the default value is in effect modified. This is generally not\nwhat was intended. A way around this is to use ``None`` as the\ndefault, and explicitly test for it in the body of the function, e.g.:\n\n def whats_on_the_telly(penguin=None):\n if penguin is None:\n penguin = []\n penguin.append("property of the zoo")\n return penguin\n\nFunction call semantics are described in more detail in section\n*Calls*. A function call always assigns values to all parameters\nmentioned in the parameter list, either from position arguments, from\nkeyword arguments, or from default values. If the form\n"``*identifier``" is present, it is initialized to a tuple receiving\nany excess positional parameters, defaulting to the empty tuple. If\nthe form "``**identifier``" is present, it is initialized to a new\ndictionary receiving any excess keyword arguments, defaulting to a new\nempty dictionary. Parameters after "``*``" or "``*identifier``" are\nkeyword-only parameters and may only be passed used keyword arguments.\n\nParameters may have annotations of the form "``: expression``"\nfollowing the parameter name. Any parameter may have an annotation\neven those of the form ``*identifier`` or ``**identifier``. Functions\nmay have "return" annotation of the form "``-> expression``" after the\nparameter list. These annotations can be any valid Python expression\nand are evaluated when the function definition is executed.\nAnnotations may be evaluated in a different order than they appear in\nthe source code. The presence of annotations does not change the\nsemantics of a function. The annotation values are available as\nvalues of a dictionary keyed by the parameters\' names in the\n``__annotations__`` attribute of the function object.\n\nIt is also possible to create anonymous functions (functions not bound\nto a name), for immediate use in expressions. This uses lambda forms,\ndescribed in section *Lambdas*. Note that the lambda form is merely a\nshorthand for a simplified function definition; a function defined in\na "``def``" statement can be passed around or assigned to another name\njust like a function defined by a lambda form. The "``def``" form is\nactually more powerful since it allows the execution of multiple\nstatements and annotations.\n\n**Programmer\'s note:** Functions are first-class objects. A "``def``"\nform executed inside a function definition defines a local function\nthat can be returned or passed around. Free variables used in the\nnested function can access the local variables of the function\ncontaining the def. See section *Naming and binding* for details.\n\n\nClass definitions\n=================\n\nA class definition defines a class object (see section *The standard\ntype hierarchy*):\n\n classdef ::= [decorators] "class" classname [inheritance] ":" suite\n inheritance ::= "(" [argument_list [","] | comprehension] ")"\n classname ::= identifier\n\nA class definition is an executable statement. The inheritance list\nusually gives a list of base classes (see *Customizing class creation*\nfor more advanced uses), so each item in the list should evaluate to a\nclass object which allows subclassing. Classes without an inheritance\nlist inherit, by default, from the base class ``object``; hence,\n\n class Foo:\n pass\n\nis equivalent to\n\n class Foo(object):\n pass\n\nThe class\'s suite is then executed in a new execution frame (see\n*Naming and binding*), using a newly created local namespace and the\noriginal global namespace. (Usually, the suite contains mostly\nfunction definitions.) When the class\'s suite finishes execution, its\nexecution frame is discarded but its local namespace is saved. [4] A\nclass object is then created using the inheritance list for the base\nclasses and the saved local namespace for the attribute dictionary.\nThe class name is bound to this class object in the original local\nnamespace.\n\nClass creation can be customized heavily using *metaclasses*.\n\nClasses can also be decorated: just like when decorating functions,\n\n @f1(arg)\n @f2\n class Foo: pass\n\nis equivalent to\n\n class Foo: pass\n Foo = f1(arg)(f2(Foo))\n\nThe evaluation rules for the decorator expressions are the same as for\nfunction decorators. The result must be a class object, which is then\nbound to the class name.\n\n**Programmer\'s note:** Variables defined in the class definition are\nclass attributes; they are shared by instances. Instance attributes\ncan be set in a method with ``self.name = value``. Both class and\ninstance attributes are accessible through the notation\n"``self.name``", and an instance attribute hides a class attribute\nwith the same name when accessed in this way. Class attributes can be\nused as defaults for instance attributes, but using mutable values\nthere can lead to unexpected results. *Descriptors* can be used to\ncreate instance variables with different implementation details.\n\nSee also:\n\n **PEP 3116** - Metaclasses in Python 3 **PEP 3129** - Class\n Decorators\n\n-[ Footnotes ]-\n\n[1] The exception is propagated to the invocation stack only if there\n is no ``finally`` clause that negates the exception.\n\n[2] Currently, control "flows off the end" except in the case of an\n exception or the execution of a ``return``, ``continue``, or\n ``break`` statement.\n\n[3] A string literal appearing as the first statement in the function\n body is transformed into the function\'s ``__doc__`` attribute and\n therefore the function\'s *docstring*.\n\n[4] A string literal appearing as the first statement in the class\n body is transformed into the namespace\'s ``__doc__`` item and\n therefore the class\'s *docstring*.\n', + 'compound': '\nCompound statements\n*******************\n\nCompound statements contain (groups of) other statements; they affect\nor control the execution of those other statements in some way. In\ngeneral, compound statements span multiple lines, although in simple\nincarnations a whole compound statement may be contained in one line.\n\nThe ``if``, ``while`` and ``for`` statements implement traditional\ncontrol flow constructs. ``try`` specifies exception handlers and/or\ncleanup code for a group of statements, while the ``with`` statement\nallows the execution of initialization and finalization code around a\nblock of code. Function and class definitions are also syntactically\ncompound statements.\n\nCompound statements consist of one or more \'clauses.\' A clause\nconsists of a header and a \'suite.\' The clause headers of a\nparticular compound statement are all at the same indentation level.\nEach clause header begins with a uniquely identifying keyword and ends\nwith a colon. A suite is a group of statements controlled by a\nclause. A suite can be one or more semicolon-separated simple\nstatements on the same line as the header, following the header\'s\ncolon, or it can be one or more indented statements on subsequent\nlines. Only the latter form of suite can contain nested compound\nstatements; the following is illegal, mostly because it wouldn\'t be\nclear to which ``if`` clause a following ``else`` clause would belong:\n\n if test1: if test2: print(x)\n\nAlso note that the semicolon binds tighter than the colon in this\ncontext, so that in the following example, either all or none of the\n``print()`` calls are executed:\n\n if x < y < z: print(x); print(y); print(z)\n\nSummarizing:\n\n compound_stmt ::= if_stmt\n | while_stmt\n | for_stmt\n | try_stmt\n | with_stmt\n | funcdef\n | classdef\n suite ::= stmt_list NEWLINE | NEWLINE INDENT statement+ DEDENT\n statement ::= stmt_list NEWLINE | compound_stmt\n stmt_list ::= simple_stmt (";" simple_stmt)* [";"]\n\nNote that statements always end in a ``NEWLINE`` possibly followed by\na ``DEDENT``. Also note that optional continuation clauses always\nbegin with a keyword that cannot start a statement, thus there are no\nambiguities (the \'dangling ``else``\' problem is solved in Python by\nrequiring nested ``if`` statements to be indented).\n\nThe formatting of the grammar rules in the following sections places\neach clause on a separate line for clarity.\n\n\nThe ``if`` statement\n====================\n\nThe ``if`` statement is used for conditional execution:\n\n if_stmt ::= "if" expression ":" suite\n ( "elif" expression ":" suite )*\n ["else" ":" suite]\n\nIt selects exactly one of the suites by evaluating the expressions one\nby one until one is found to be true (see section *Boolean operations*\nfor the definition of true and false); then that suite is executed\n(and no other part of the ``if`` statement is executed or evaluated).\nIf all expressions are false, the suite of the ``else`` clause, if\npresent, is executed.\n\n\nThe ``while`` statement\n=======================\n\nThe ``while`` statement is used for repeated execution as long as an\nexpression is true:\n\n while_stmt ::= "while" expression ":" suite\n ["else" ":" suite]\n\nThis repeatedly tests the expression and, if it is true, executes the\nfirst suite; if the expression is false (which may be the first time\nit is tested) the suite of the ``else`` clause, if present, is\nexecuted and the loop terminates.\n\nA ``break`` statement executed in the first suite terminates the loop\nwithout executing the ``else`` clause\'s suite. A ``continue``\nstatement executed in the first suite skips the rest of the suite and\ngoes back to testing the expression.\n\n\nThe ``for`` statement\n=====================\n\nThe ``for`` statement is used to iterate over the elements of a\nsequence (such as a string, tuple or list) or other iterable object:\n\n for_stmt ::= "for" target_list "in" expression_list ":" suite\n ["else" ":" suite]\n\nThe expression list is evaluated once; it should yield an iterable\nobject. An iterator is created for the result of the\n``expression_list``. The suite is then executed once for each item\nprovided by the iterator, in the order of ascending indices. Each\nitem in turn is assigned to the target list using the standard rules\nfor assignments (see *Assignment statements*), and then the suite is\nexecuted. When the items are exhausted (which is immediately when the\nsequence is empty or an iterator raises a ``StopIteration``\nexception), the suite in the ``else`` clause, if present, is executed,\nand the loop terminates.\n\nA ``break`` statement executed in the first suite terminates the loop\nwithout executing the ``else`` clause\'s suite. A ``continue``\nstatement executed in the first suite skips the rest of the suite and\ncontinues with the next item, or with the ``else`` clause if there was\nno next item.\n\nThe suite may assign to the variable(s) in the target list; this does\nnot affect the next item assigned to it.\n\nNames in the target list are not deleted when the loop is finished,\nbut if the sequence is empty, it will not have been assigned to at all\nby the loop. Hint: the built-in function ``range()`` returns an\niterator of integers suitable to emulate the effect of Pascal\'s ``for\ni := a to b do``; e.g., ``list(range(3))`` returns the list ``[0, 1,\n2]``.\n\nNote: There is a subtlety when the sequence is being modified by the loop\n (this can only occur for mutable sequences, i.e. lists). An\n internal counter is used to keep track of which item is used next,\n and this is incremented on each iteration. When this counter has\n reached the length of the sequence the loop terminates. This means\n that if the suite deletes the current (or a previous) item from the\n sequence, the next item will be skipped (since it gets the index of\n the current item which has already been treated). Likewise, if the\n suite inserts an item in the sequence before the current item, the\n current item will be treated again the next time through the loop.\n This can lead to nasty bugs that can be avoided by making a\n temporary copy using a slice of the whole sequence, e.g.,\n\n for x in a[:]:\n if x < 0: a.remove(x)\n\n\nThe ``try`` statement\n=====================\n\nThe ``try`` statement specifies exception handlers and/or cleanup code\nfor a group of statements:\n\n try_stmt ::= try1_stmt | try2_stmt\n try1_stmt ::= "try" ":" suite\n ("except" [expression ["as" target]] ":" suite)+\n ["else" ":" suite]\n ["finally" ":" suite]\n try2_stmt ::= "try" ":" suite\n "finally" ":" suite\n\nThe ``except`` clause(s) specify one or more exception handlers. When\nno exception occurs in the ``try`` clause, no exception handler is\nexecuted. When an exception occurs in the ``try`` suite, a search for\nan exception handler is started. This search inspects the except\nclauses in turn until one is found that matches the exception. An\nexpression-less except clause, if present, must be last; it matches\nany exception. For an except clause with an expression, that\nexpression is evaluated, and the clause matches the exception if the\nresulting object is "compatible" with the exception. An object is\ncompatible with an exception if it is the class or a base class of the\nexception object or a tuple containing an item compatible with the\nexception.\n\nIf no except clause matches the exception, the search for an exception\nhandler continues in the surrounding code and on the invocation stack.\n[1]\n\nIf the evaluation of an expression in the header of an except clause\nraises an exception, the original search for a handler is canceled and\na search starts for the new exception in the surrounding code and on\nthe call stack (it is treated as if the entire ``try`` statement\nraised the exception).\n\nWhen a matching except clause is found, the exception is assigned to\nthe target specified after the ``as`` keyword in that except clause,\nif present, and the except clause\'s suite is executed. All except\nclauses must have an executable block. When the end of this block is\nreached, execution continues normally after the entire try statement.\n(This means that if two nested handlers exist for the same exception,\nand the exception occurs in the try clause of the inner handler, the\nouter handler will not handle the exception.)\n\nWhen an exception has been assigned using ``as target``, it is cleared\nat the end of the except clause. This is as if\n\n except E as N:\n foo\n\nwas translated to\n\n except E as N:\n try:\n foo\n finally:\n del N\n\nThis means the exception must be assigned to a different name to be\nable to refer to it after the except clause. Exceptions are cleared\nbecause with the traceback attached to them, they form a reference\ncycle with the stack frame, keeping all locals in that frame alive\nuntil the next garbage collection occurs.\n\nBefore an except clause\'s suite is executed, details about the\nexception are stored in the ``sys`` module and can be access via\n``sys.exc_info()``. ``sys.exc_info()`` returns a 3-tuple consisting of\nthe exception class, the exception instance and a traceback object\n(see section *The standard type hierarchy*) identifying the point in\nthe program where the exception occurred. ``sys.exc_info()`` values\nare restored to their previous values (before the call) when returning\nfrom a function that handled an exception.\n\nThe optional ``else`` clause is executed if and when control flows off\nthe end of the ``try`` clause. [2] Exceptions in the ``else`` clause\nare not handled by the preceding ``except`` clauses.\n\nIf ``finally`` is present, it specifies a \'cleanup\' handler. The\n``try`` clause is executed, including any ``except`` and ``else``\nclauses. If an exception occurs in any of the clauses and is not\nhandled, the exception is temporarily saved. The ``finally`` clause is\nexecuted. If there is a saved exception, it is re-raised at the end\nof the ``finally`` clause. If the ``finally`` clause raises another\nexception or executes a ``return`` or ``break`` statement, the saved\nexception is lost. The exception information is not available to the\nprogram during execution of the ``finally`` clause.\n\nWhen a ``return``, ``break`` or ``continue`` statement is executed in\nthe ``try`` suite of a ``try``...``finally`` statement, the\n``finally`` clause is also executed \'on the way out.\' A ``continue``\nstatement is illegal in the ``finally`` clause. (The reason is a\nproblem with the current implementation --- this restriction may be\nlifted in the future).\n\nAdditional information on exceptions can be found in section\n*Exceptions*, and information on using the ``raise`` statement to\ngenerate exceptions may be found in section *The raise statement*.\n\n\nThe ``with`` statement\n======================\n\nThe ``with`` statement is used to wrap the execution of a block with\nmethods defined by a context manager (see section *With Statement\nContext Managers*). This allows common\n``try``...``except``...``finally`` usage patterns to be encapsulated\nfor convenient reuse.\n\n with_stmt ::= "with" with_item ("," with_item)* ":" suite\n with_item ::= expression ["as" target]\n\nThe execution of the ``with`` statement with one "item" proceeds as\nfollows:\n\n1. The context expression (the expression given in the ``with_item``)\n is evaluated to obtain a context manager.\n\n2. The context manager\'s ``__exit__()`` is loaded for later use.\n\n3. The context manager\'s ``__enter__()`` method is invoked.\n\n4. If a target was included in the ``with`` statement, the return\n value from ``__enter__()`` is assigned to it.\n\n Note: The ``with`` statement guarantees that if the ``__enter__()``\n method returns without an error, then ``__exit__()`` will always\n be called. Thus, if an error occurs during the assignment to the\n target list, it will be treated the same as an error occurring\n within the suite would be. See step 6 below.\n\n5. The suite is executed.\n\n6. The context manager\'s ``__exit__()`` method is invoked. If an\n exception caused the suite to be exited, its type, value, and\n traceback are passed as arguments to ``__exit__()``. Otherwise,\n three ``None`` arguments are supplied.\n\n If the suite was exited due to an exception, and the return value\n from the ``__exit__()`` method was false, the exception is\n reraised. If the return value was true, the exception is\n suppressed, and execution continues with the statement following\n the ``with`` statement.\n\n If the suite was exited for any reason other than an exception, the\n return value from ``__exit__()`` is ignored, and execution proceeds\n at the normal location for the kind of exit that was taken.\n\nWith more than one item, the context managers are processed as if\nmultiple ``with`` statements were nested:\n\n with A() as a, B() as b:\n suite\n\nis equivalent to\n\n with A() as a:\n with B() as b:\n suite\n\nChanged in version 3.1: Support for multiple context expressions.\n\nSee also:\n\n **PEP 0343** - The "with" statement\n The specification, background, and examples for the Python\n ``with`` statement.\n\n\nFunction definitions\n====================\n\nA function definition defines a user-defined function object (see\nsection *The standard type hierarchy*):\n\n funcdef ::= [decorators] "def" funcname "(" [parameter_list] ")" ["->" expression] ":" suite\n decorators ::= decorator+\n decorator ::= "@" dotted_name ["(" [argument_list [","]] ")"] NEWLINE\n dotted_name ::= identifier ("." identifier)*\n parameter_list ::= (defparameter ",")*\n ( "*" [parameter] ("," defparameter)*\n [, "**" parameter]\n | "**" parameter\n | defparameter [","] )\n parameter ::= identifier [":" expression]\n defparameter ::= parameter ["=" expression]\n funcname ::= identifier\n\nA function definition is an executable statement. Its execution binds\nthe function name in the current local namespace to a function object\n(a wrapper around the executable code for the function). This\nfunction object contains a reference to the current global namespace\nas the global namespace to be used when the function is called.\n\nThe function definition does not execute the function body; this gets\nexecuted only when the function is called. [3]\n\nA function definition may be wrapped by one or more *decorator*\nexpressions. Decorator expressions are evaluated when the function is\ndefined, in the scope that contains the function definition. The\nresult must be a callable, which is invoked with the function object\nas the only argument. The returned value is bound to the function name\ninstead of the function object. Multiple decorators are applied in\nnested fashion. For example, the following code\n\n @f1(arg)\n @f2\n def func(): pass\n\nis equivalent to\n\n def func(): pass\n func = f1(arg)(f2(func))\n\nWhen one or more parameters have the form *parameter* ``=``\n*expression*, the function is said to have "default parameter values."\nFor a parameter with a default value, the corresponding argument may\nbe omitted from a call, in which case the parameter\'s default value is\nsubstituted. If a parameter has a default value, all following\nparameters up until the "``*``" must also have a default value ---\nthis is a syntactic restriction that is not expressed by the grammar.\n\n**Default parameter values are evaluated when the function definition\nis executed.** This means that the expression is evaluated once, when\nthe function is defined, and that that same "pre-computed" value is\nused for each call. This is especially important to understand when a\ndefault parameter is a mutable object, such as a list or a dictionary:\nif the function modifies the object (e.g. by appending an item to a\nlist), the default value is in effect modified. This is generally not\nwhat was intended. A way around this is to use ``None`` as the\ndefault, and explicitly test for it in the body of the function, e.g.:\n\n def whats_on_the_telly(penguin=None):\n if penguin is None:\n penguin = []\n penguin.append("property of the zoo")\n return penguin\n\nFunction call semantics are described in more detail in section\n*Calls*. A function call always assigns values to all parameters\nmentioned in the parameter list, either from position arguments, from\nkeyword arguments, or from default values. If the form\n"``*identifier``" is present, it is initialized to a tuple receiving\nany excess positional parameters, defaulting to the empty tuple. If\nthe form "``**identifier``" is present, it is initialized to a new\ndictionary receiving any excess keyword arguments, defaulting to a new\nempty dictionary. Parameters after "``*``" or "``*identifier``" are\nkeyword-only parameters and may only be passed used keyword arguments.\n\nParameters may have annotations of the form "``: expression``"\nfollowing the parameter name. Any parameter may have an annotation\neven those of the form ``*identifier`` or ``**identifier``. Functions\nmay have "return" annotation of the form "``-> expression``" after the\nparameter list. These annotations can be any valid Python expression\nand are evaluated when the function definition is executed.\nAnnotations may be evaluated in a different order than they appear in\nthe source code. The presence of annotations does not change the\nsemantics of a function. The annotation values are available as\nvalues of a dictionary keyed by the parameters\' names in the\n``__annotations__`` attribute of the function object.\n\nIt is also possible to create anonymous functions (functions not bound\nto a name), for immediate use in expressions. This uses lambda forms,\ndescribed in section *Lambdas*. Note that the lambda form is merely a\nshorthand for a simplified function definition; a function defined in\na "``def``" statement can be passed around or assigned to another name\njust like a function defined by a lambda form. The "``def``" form is\nactually more powerful since it allows the execution of multiple\nstatements and annotations.\n\n**Programmer\'s note:** Functions are first-class objects. A "``def``"\nform executed inside a function definition defines a local function\nthat can be returned or passed around. Free variables used in the\nnested function can access the local variables of the function\ncontaining the def. See section *Naming and binding* for details.\n\n\nClass definitions\n=================\n\nA class definition defines a class object (see section *The standard\ntype hierarchy*):\n\n classdef ::= [decorators] "class" classname [inheritance] ":" suite\n inheritance ::= "(" [argument_list [","] | comprehension] ")"\n classname ::= identifier\n\nA class definition is an executable statement. The inheritance list\nusually gives a list of base classes (see *Customizing class creation*\nfor more advanced uses), so each item in the list should evaluate to a\nclass object which allows subclassing. Classes without an inheritance\nlist inherit, by default, from the base class ``object``; hence,\n\n class Foo:\n pass\n\nis equivalent to\n\n class Foo(object):\n pass\n\nThe class\'s suite is then executed in a new execution frame (see\n*Naming and binding*), using a newly created local namespace and the\noriginal global namespace. (Usually, the suite contains mostly\nfunction definitions.) When the class\'s suite finishes execution, its\nexecution frame is discarded but its local namespace is saved. [4] A\nclass object is then created using the inheritance list for the base\nclasses and the saved local namespace for the attribute dictionary.\nThe class name is bound to this class object in the original local\nnamespace.\n\nClass creation can be customized heavily using *metaclasses*.\n\nClasses can also be decorated: just like when decorating functions,\n\n @f1(arg)\n @f2\n class Foo: pass\n\nis equivalent to\n\n class Foo: pass\n Foo = f1(arg)(f2(Foo))\n\nThe evaluation rules for the decorator expressions are the same as for\nfunction decorators. The result must be a class object, which is then\nbound to the class name.\n\n**Programmer\'s note:** Variables defined in the class definition are\nclass attributes; they are shared by instances. Instance attributes\ncan be set in a method with ``self.name = value``. Both class and\ninstance attributes are accessible through the notation\n"``self.name``", and an instance attribute hides a class attribute\nwith the same name when accessed in this way. Class attributes can be\nused as defaults for instance attributes, but using mutable values\nthere can lead to unexpected results. *Descriptors* can be used to\ncreate instance variables with different implementation details.\n\nSee also:\n\n **PEP 3115** - Metaclasses in Python 3 **PEP 3129** - Class\n Decorators\n\n-[ Footnotes ]-\n\n[1] The exception is propagated to the invocation stack only if there\n is no ``finally`` clause that negates the exception.\n\n[2] Currently, control "flows off the end" except in the case of an\n exception or the execution of a ``return``, ``continue``, or\n ``break`` statement.\n\n[3] A string literal appearing as the first statement in the function\n body is transformed into the function\'s ``__doc__`` attribute and\n therefore the function\'s *docstring*.\n\n[4] A string literal appearing as the first statement in the class\n body is transformed into the namespace\'s ``__doc__`` item and\n therefore the class\'s *docstring*.\n', 'context-managers': '\nWith Statement Context Managers\n*******************************\n\nA *context manager* is an object that defines the runtime context to\nbe established when executing a ``with`` statement. The context\nmanager handles the entry into, and the exit from, the desired runtime\ncontext for the execution of the block of code. Context managers are\nnormally invoked using the ``with`` statement (described in section\n*The with statement*), but can also be used by directly invoking their\nmethods.\n\nTypical uses of context managers include saving and restoring various\nkinds of global state, locking and unlocking resources, closing opened\nfiles, etc.\n\nFor more information on context managers, see *Context Manager Types*.\n\nobject.__enter__(self)\n\n Enter the runtime context related to this object. The ``with``\n statement will bind this method\'s return value to the target(s)\n specified in the ``as`` clause of the statement, if any.\n\nobject.__exit__(self, exc_type, exc_value, traceback)\n\n Exit the runtime context related to this object. The parameters\n describe the exception that caused the context to be exited. If the\n context was exited without an exception, all three arguments will\n be ``None``.\n\n If an exception is supplied, and the method wishes to suppress the\n exception (i.e., prevent it from being propagated), it should\n return a true value. Otherwise, the exception will be processed\n normally upon exit from this method.\n\n Note that ``__exit__()`` methods should not reraise the passed-in\n exception; this is the caller\'s responsibility.\n\nSee also:\n\n **PEP 0343** - The "with" statement\n The specification, background, and examples for the Python\n ``with`` statement.\n', 'continue': '\nThe ``continue`` statement\n**************************\n\n continue_stmt ::= "continue"\n\n``continue`` may only occur syntactically nested in a ``for`` or\n``while`` loop, but not nested in a function or class definition or\n``finally`` clause within that loop. It continues with the next cycle\nof the nearest enclosing loop.\n\nWhen ``continue`` passes control out of a ``try`` statement with a\n``finally`` clause, that ``finally`` clause is executed before really\nstarting the next loop cycle.\n', 'conversions': '\nArithmetic conversions\n**********************\n\nWhen a description of an arithmetic operator below uses the phrase\n"the numeric arguments are converted to a common type," this means\nthat the operator implementation for built-in types works that way:\n\n* If either argument is a complex number, the other is converted to\n complex;\n\n* otherwise, if either argument is a floating point number, the other\n is converted to floating point;\n\n* otherwise, both must be integers and no conversion is necessary.\n\nSome additional rules apply for certain operators (e.g., a string left\nargument to the \'%\' operator). Extensions must define their own\nconversion behavior.\n', @@ -29,7 +29,7 @@ 'dynamic-features': '\nInteraction with dynamic features\n*********************************\n\nThere are several cases where Python statements are illegal when used\nin conjunction with nested scopes that contain free variables.\n\nIf a variable is referenced in an enclosing scope, it is illegal to\ndelete the name. An error will be reported at compile time.\n\nIf the wild card form of import --- ``import *`` --- is used in a\nfunction and the function contains or is a nested block with free\nvariables, the compiler will raise a ``SyntaxError``.\n\nThe ``eval()`` and ``exec()`` functions do not have access to the full\nenvironment for resolving names. Names may be resolved in the local\nand global namespaces of the caller. Free variables are not resolved\nin the nearest enclosing namespace, but in the global namespace. [1]\nThe ``exec()`` and ``eval()`` functions have optional arguments to\noverride the global and local namespace. If only one namespace is\nspecified, it is used for both.\n', 'else': '\nThe ``if`` statement\n********************\n\nThe ``if`` statement is used for conditional execution:\n\n if_stmt ::= "if" expression ":" suite\n ( "elif" expression ":" suite )*\n ["else" ":" suite]\n\nIt selects exactly one of the suites by evaluating the expressions one\nby one until one is found to be true (see section *Boolean operations*\nfor the definition of true and false); then that suite is executed\n(and no other part of the ``if`` statement is executed or evaluated).\nIf all expressions are false, the suite of the ``else`` clause, if\npresent, is executed.\n', 'exceptions': '\nExceptions\n**********\n\nExceptions are a means of breaking out of the normal flow of control\nof a code block in order to handle errors or other exceptional\nconditions. An exception is *raised* at the point where the error is\ndetected; it may be *handled* by the surrounding code block or by any\ncode block that directly or indirectly invoked the code block where\nthe error occurred.\n\nThe Python interpreter raises an exception when it detects a run-time\nerror (such as division by zero). A Python program can also\nexplicitly raise an exception with the ``raise`` statement. Exception\nhandlers are specified with the ``try`` ... ``except`` statement. The\n``finally`` clause of such a statement can be used to specify cleanup\ncode which does not handle the exception, but is executed whether an\nexception occurred or not in the preceding code.\n\nPython uses the "termination" model of error handling: an exception\nhandler can find out what happened and continue execution at an outer\nlevel, but it cannot repair the cause of the error and retry the\nfailing operation (except by re-entering the offending piece of code\nfrom the top).\n\nWhen an exception is not handled at all, the interpreter terminates\nexecution of the program, or returns to its interactive main loop. In\neither case, it prints a stack backtrace, except when the exception is\n``SystemExit``.\n\nExceptions are identified by class instances. The ``except`` clause\nis selected depending on the class of the instance: it must reference\nthe class of the instance or a base class thereof. The instance can\nbe received by the handler and can carry additional information about\nthe exceptional condition.\n\nNote: Exception messages are not part of the Python API. Their contents\n may change from one version of Python to the next without warning\n and should not be relied on by code which will run under multiple\n versions of the interpreter.\n\nSee also the description of the ``try`` statement in section *The try\nstatement* and ``raise`` statement in section *The raise statement*.\n\n-[ Footnotes ]-\n\n[1] This limitation occurs because the code that is executed by these\n operations is not available at the time the module is compiled.\n', - 'execmodel': '\nExecution model\n***************\n\n\nNaming and binding\n==================\n\n*Names* refer to objects. Names are introduced by name binding\noperations. Each occurrence of a name in the program text refers to\nthe *binding* of that name established in the innermost function block\ncontaining the use.\n\nA *block* is a piece of Python program text that is executed as a\nunit. The following are blocks: a module, a function body, and a class\ndefinition. Each command typed interactively is a block. A script\nfile (a file given as standard input to the interpreter or specified\non the interpreter command line the first argument) is a code block.\nA script command (a command specified on the interpreter command line\nwith the \'**-c**\' option) is a code block. The string argument passed\nto the built-in functions ``eval()`` and ``exec()`` is a code block.\n\nA code block is executed in an *execution frame*. A frame contains\nsome administrative information (used for debugging) and determines\nwhere and how execution continues after the code block\'s execution has\ncompleted.\n\nA *scope* defines the visibility of a name within a block. If a local\nvariable is defined in a block, its scope includes that block. If the\ndefinition occurs in a function block, the scope extends to any blocks\ncontained within the defining one, unless a contained block introduces\na different binding for the name. The scope of names defined in a\nclass block is limited to the class block; it does not extend to the\ncode blocks of methods -- this includes comprehensions and generator\nexpressions since they are implemented using a function scope. This\nmeans that the following will fail:\n\n class A:\n a = 42\n b = list(a + i for i in range(10))\n\nWhen a name is used in a code block, it is resolved using the nearest\nenclosing scope. The set of all such scopes visible to a code block\nis called the block\'s *environment*.\n\nIf a name is bound in a block, it is a local variable of that block,\nunless declared as ``nonlocal``. If a name is bound at the module\nlevel, it is a global variable. (The variables of the module code\nblock are local and global.) If a variable is used in a code block\nbut not defined there, it is a *free variable*.\n\nWhen a name is not found at all, a ``NameError`` exception is raised.\nIf the name refers to a local variable that has not been bound, a\n``UnboundLocalError`` exception is raised. ``UnboundLocalError`` is a\nsubclass of ``NameError``.\n\nThe following constructs bind names: formal parameters to functions,\n``import`` statements, class and function definitions (these bind the\nclass or function name in the defining block), and targets that are\nidentifiers if occurring in an assignment, ``for`` loop header, or\nafter ``as`` in a ``with`` statement or ``except`` clause. The\n``import`` statement of the form ``from ... import *`` binds all names\ndefined in the imported module, except those beginning with an\nunderscore. This form may only be used at the module level.\n\nA target occurring in a ``del`` statement is also considered bound for\nthis purpose (though the actual semantics are to unbind the name). It\nis illegal to unbind a name that is referenced by an enclosing scope;\nthe compiler will report a ``SyntaxError``.\n\nEach assignment or import statement occurs within a block defined by a\nclass or function definition or at the module level (the top-level\ncode block).\n\nIf a name binding operation occurs anywhere within a code block, all\nuses of the name within the block are treated as references to the\ncurrent block. This can lead to errors when a name is used within a\nblock before it is bound. This rule is subtle. Python lacks\ndeclarations and allows name binding operations to occur anywhere\nwithin a code block. The local variables of a code block can be\ndetermined by scanning the entire text of the block for name binding\noperations.\n\nIf the ``global`` statement occurs within a block, all uses of the\nname specified in the statement refer to the binding of that name in\nthe top-level namespace. Names are resolved in the top-level\nnamespace by searching the global namespace, i.e. the namespace of the\nmodule containing the code block, and the builtins namespace, the\nnamespace of the module ``builtins``. The global namespace is\nsearched first. If the name is not found there, the builtins\nnamespace is searched. The global statement must precede all uses of\nthe name.\n\nThe builtins namespace associated with the execution of a code block\nis actually found by looking up the name ``__builtins__`` in its\nglobal namespace; this should be a dictionary or a module (in the\nlatter case the module\'s dictionary is used). By default, when in the\n``__main__`` module, ``__builtins__`` is the built-in module\n``builtins``; when in any other module, ``__builtins__`` is an alias\nfor the dictionary of the ``builtins`` module itself.\n``__builtins__`` can be set to a user-created dictionary to create a\nweak form of restricted execution.\n\n**CPython implementation detail:** Users should not touch\n``__builtins__``; it is strictly an implementation detail. Users\nwanting to override values in the builtins namespace should ``import``\nthe ``builtins`` module and modify its attributes appropriately.\n\nThe namespace for a module is automatically created the first time a\nmodule is imported. The main module for a script is always called\n``__main__``.\n\nThe ``global`` statement has the same scope as a name binding\noperation in the same block. If the nearest enclosing scope for a\nfree variable contains a global statement, the free variable is\ntreated as a global.\n\nA class definition is an executable statement that may use and define\nnames. These references follow the normal rules for name resolution.\nThe namespace of the class definition becomes the attribute dictionary\nof the class. Names defined at the class scope are not visible in\nmethods.\n\n\nInteraction with dynamic features\n---------------------------------\n\nThere are several cases where Python statements are illegal when used\nin conjunction with nested scopes that contain free variables.\n\nIf a variable is referenced in an enclosing scope, it is illegal to\ndelete the name. An error will be reported at compile time.\n\nIf the wild card form of import --- ``import *`` --- is used in a\nfunction and the function contains or is a nested block with free\nvariables, the compiler will raise a ``SyntaxError``.\n\nThe ``eval()`` and ``exec()`` functions do not have access to the full\nenvironment for resolving names. Names may be resolved in the local\nand global namespaces of the caller. Free variables are not resolved\nin the nearest enclosing namespace, but in the global namespace. [1]\nThe ``exec()`` and ``eval()`` functions have optional arguments to\noverride the global and local namespace. If only one namespace is\nspecified, it is used for both.\n\n\nExceptions\n==========\n\nExceptions are a means of breaking out of the normal flow of control\nof a code block in order to handle errors or other exceptional\nconditions. An exception is *raised* at the point where the error is\ndetected; it may be *handled* by the surrounding code block or by any\ncode block that directly or indirectly invoked the code block where\nthe error occurred.\n\nThe Python interpreter raises an exception when it detects a run-time\nerror (such as division by zero). A Python program can also\nexplicitly raise an exception with the ``raise`` statement. Exception\nhandlers are specified with the ``try`` ... ``except`` statement. The\n``finally`` clause of such a statement can be used to specify cleanup\ncode which does not handle the exception, but is executed whether an\nexception occurred or not in the preceding code.\n\nPython uses the "termination" model of error handling: an exception\nhandler can find out what happened and continue execution at an outer\nlevel, but it cannot repair the cause of the error and retry the\nfailing operation (except by re-entering the offending piece of code\nfrom the top).\n\nWhen an exception is not handled at all, the interpreter terminates\nexecution of the program, or returns to its interactive main loop. In\neither case, it prints a stack backtrace, except when the exception is\n``SystemExit``.\n\nExceptions are identified by class instances. The ``except`` clause\nis selected depending on the class of the instance: it must reference\nthe class of the instance or a base class thereof. The instance can\nbe received by the handler and can carry additional information about\nthe exceptional condition.\n\nNote: Exception messages are not part of the Python API. Their contents\n may change from one version of Python to the next without warning\n and should not be relied on by code which will run under multiple\n versions of the interpreter.\n\nSee also the description of the ``try`` statement in section *The try\nstatement* and ``raise`` statement in section *The raise statement*.\n\n-[ Footnotes ]-\n\n[1] This limitation occurs because the code that is executed by these\n operations is not available at the time the module is compiled.\n', + 'execmodel': '\nExecution model\n***************\n\n\nNaming and binding\n==================\n\n*Names* refer to objects. Names are introduced by name binding\noperations. Each occurrence of a name in the program text refers to\nthe *binding* of that name established in the innermost function block\ncontaining the use.\n\nA *block* is a piece of Python program text that is executed as a\nunit. The following are blocks: a module, a function body, and a class\ndefinition. Each command typed interactively is a block. A script\nfile (a file given as standard input to the interpreter or specified\non the interpreter command line the first argument) is a code block.\nA script command (a command specified on the interpreter command line\nwith the \'**-c**\' option) is a code block. The string argument passed\nto the built-in functions ``eval()`` and ``exec()`` is a code block.\n\nA code block is executed in an *execution frame*. A frame contains\nsome administrative information (used for debugging) and determines\nwhere and how execution continues after the code block\'s execution has\ncompleted.\n\nA *scope* defines the visibility of a name within a block. If a local\nvariable is defined in a block, its scope includes that block. If the\ndefinition occurs in a function block, the scope extends to any blocks\ncontained within the defining one, unless a contained block introduces\na different binding for the name. The scope of names defined in a\nclass block is limited to the class block; it does not extend to the\ncode blocks of methods -- this includes comprehensions and generator\nexpressions since they are implemented using a function scope. This\nmeans that the following will fail:\n\n class A:\n a = 42\n b = list(a + i for i in range(10))\n\nWhen a name is used in a code block, it is resolved using the nearest\nenclosing scope. The set of all such scopes visible to a code block\nis called the block\'s *environment*.\n\nIf a name is bound in a block, it is a local variable of that block,\nunless declared as ``nonlocal``. If a name is bound at the module\nlevel, it is a global variable. (The variables of the module code\nblock are local and global.) If a variable is used in a code block\nbut not defined there, it is a *free variable*.\n\nWhen a name is not found at all, a ``NameError`` exception is raised.\nIf the name refers to a local variable that has not been bound, a\n``UnboundLocalError`` exception is raised. ``UnboundLocalError`` is a\nsubclass of ``NameError``.\n\nThe following constructs bind names: formal parameters to functions,\n``import`` statements, class and function definitions (these bind the\nclass or function name in the defining block), and targets that are\nidentifiers if occurring in an assignment, ``for`` loop header, or\nafter ``as`` in a ``with`` statement or ``except`` clause. The\n``import`` statement of the form ``from ... import *`` binds all names\ndefined in the imported module, except those beginning with an\nunderscore. This form may only be used at the module level.\n\nA target occurring in a ``del`` statement is also considered bound for\nthis purpose (though the actual semantics are to unbind the name).\n\nEach assignment or import statement occurs within a block defined by a\nclass or function definition or at the module level (the top-level\ncode block).\n\nIf a name binding operation occurs anywhere within a code block, all\nuses of the name within the block are treated as references to the\ncurrent block. This can lead to errors when a name is used within a\nblock before it is bound. This rule is subtle. Python lacks\ndeclarations and allows name binding operations to occur anywhere\nwithin a code block. The local variables of a code block can be\ndetermined by scanning the entire text of the block for name binding\noperations.\n\nIf the ``global`` statement occurs within a block, all uses of the\nname specified in the statement refer to the binding of that name in\nthe top-level namespace. Names are resolved in the top-level\nnamespace by searching the global namespace, i.e. the namespace of the\nmodule containing the code block, and the builtins namespace, the\nnamespace of the module ``builtins``. The global namespace is\nsearched first. If the name is not found there, the builtins\nnamespace is searched. The global statement must precede all uses of\nthe name.\n\nThe builtins namespace associated with the execution of a code block\nis actually found by looking up the name ``__builtins__`` in its\nglobal namespace; this should be a dictionary or a module (in the\nlatter case the module\'s dictionary is used). By default, when in the\n``__main__`` module, ``__builtins__`` is the built-in module\n``builtins``; when in any other module, ``__builtins__`` is an alias\nfor the dictionary of the ``builtins`` module itself.\n``__builtins__`` can be set to a user-created dictionary to create a\nweak form of restricted execution.\n\n**CPython implementation detail:** Users should not touch\n``__builtins__``; it is strictly an implementation detail. Users\nwanting to override values in the builtins namespace should ``import``\nthe ``builtins`` module and modify its attributes appropriately.\n\nThe namespace for a module is automatically created the first time a\nmodule is imported. The main module for a script is always called\n``__main__``.\n\nThe ``global`` statement has the same scope as a name binding\noperation in the same block. If the nearest enclosing scope for a\nfree variable contains a global statement, the free variable is\ntreated as a global.\n\nA class definition is an executable statement that may use and define\nnames. These references follow the normal rules for name resolution.\nThe namespace of the class definition becomes the attribute dictionary\nof the class. Names defined at the class scope are not visible in\nmethods.\n\n\nInteraction with dynamic features\n---------------------------------\n\nThere are several cases where Python statements are illegal when used\nin conjunction with nested scopes that contain free variables.\n\nIf a variable is referenced in an enclosing scope, it is illegal to\ndelete the name. An error will be reported at compile time.\n\nIf the wild card form of import --- ``import *`` --- is used in a\nfunction and the function contains or is a nested block with free\nvariables, the compiler will raise a ``SyntaxError``.\n\nThe ``eval()`` and ``exec()`` functions do not have access to the full\nenvironment for resolving names. Names may be resolved in the local\nand global namespaces of the caller. Free variables are not resolved\nin the nearest enclosing namespace, but in the global namespace. [1]\nThe ``exec()`` and ``eval()`` functions have optional arguments to\noverride the global and local namespace. If only one namespace is\nspecified, it is used for both.\n\n\nExceptions\n==========\n\nExceptions are a means of breaking out of the normal flow of control\nof a code block in order to handle errors or other exceptional\nconditions. An exception is *raised* at the point where the error is\ndetected; it may be *handled* by the surrounding code block or by any\ncode block that directly or indirectly invoked the code block where\nthe error occurred.\n\nThe Python interpreter raises an exception when it detects a run-time\nerror (such as division by zero). A Python program can also\nexplicitly raise an exception with the ``raise`` statement. Exception\nhandlers are specified with the ``try`` ... ``except`` statement. The\n``finally`` clause of such a statement can be used to specify cleanup\ncode which does not handle the exception, but is executed whether an\nexception occurred or not in the preceding code.\n\nPython uses the "termination" model of error handling: an exception\nhandler can find out what happened and continue execution at an outer\nlevel, but it cannot repair the cause of the error and retry the\nfailing operation (except by re-entering the offending piece of code\nfrom the top).\n\nWhen an exception is not handled at all, the interpreter terminates\nexecution of the program, or returns to its interactive main loop. In\neither case, it prints a stack backtrace, except when the exception is\n``SystemExit``.\n\nExceptions are identified by class instances. The ``except`` clause\nis selected depending on the class of the instance: it must reference\nthe class of the instance or a base class thereof. The instance can\nbe received by the handler and can carry additional information about\nthe exceptional condition.\n\nNote: Exception messages are not part of the Python API. Their contents\n may change from one version of Python to the next without warning\n and should not be relied on by code which will run under multiple\n versions of the interpreter.\n\nSee also the description of the ``try`` statement in section *The try\nstatement* and ``raise`` statement in section *The raise statement*.\n\n-[ Footnotes ]-\n\n[1] This limitation occurs because the code that is executed by these\n operations is not available at the time the module is compiled.\n', 'exprlists': '\nExpression lists\n****************\n\n expression_list ::= expression ( "," expression )* [","]\n\nAn expression list containing at least one comma yields a tuple. The\nlength of the tuple is the number of expressions in the list. The\nexpressions are evaluated from left to right.\n\nThe trailing comma is required only to create a single tuple (a.k.a. a\n*singleton*); it is optional in all other cases. A single expression\nwithout a trailing comma doesn\'t create a tuple, but rather yields the\nvalue of that expression. (To create an empty tuple, use an empty pair\nof parentheses: ``()``.)\n', 'floating': '\nFloating point literals\n***********************\n\nFloating point literals are described by the following lexical\ndefinitions:\n\n floatnumber ::= pointfloat | exponentfloat\n pointfloat ::= [intpart] fraction | intpart "."\n exponentfloat ::= (intpart | pointfloat) exponent\n intpart ::= digit+\n fraction ::= "." digit+\n exponent ::= ("e" | "E") ["+" | "-"] digit+\n\nNote that the integer and exponent parts are always interpreted using\nradix 10. For example, ``077e010`` is legal, and denotes the same\nnumber as ``77e10``. The allowed range of floating point literals is\nimplementation-dependent. Some examples of floating point literals:\n\n 3.14 10. .001 1e100 3.14e-10 0e0\n\nNote that numeric literals do not include a sign; a phrase like ``-1``\nis actually an expression composed of the unary operator ``-`` and the\nliteral ``1``.\n', 'for': '\nThe ``for`` statement\n*********************\n\nThe ``for`` statement is used to iterate over the elements of a\nsequence (such as a string, tuple or list) or other iterable object:\n\n for_stmt ::= "for" target_list "in" expression_list ":" suite\n ["else" ":" suite]\n\nThe expression list is evaluated once; it should yield an iterable\nobject. An iterator is created for the result of the\n``expression_list``. The suite is then executed once for each item\nprovided by the iterator, in the order of ascending indices. Each\nitem in turn is assigned to the target list using the standard rules\nfor assignments (see *Assignment statements*), and then the suite is\nexecuted. When the items are exhausted (which is immediately when the\nsequence is empty or an iterator raises a ``StopIteration``\nexception), the suite in the ``else`` clause, if present, is executed,\nand the loop terminates.\n\nA ``break`` statement executed in the first suite terminates the loop\nwithout executing the ``else`` clause\'s suite. A ``continue``\nstatement executed in the first suite skips the rest of the suite and\ncontinues with the next item, or with the ``else`` clause if there was\nno next item.\n\nThe suite may assign to the variable(s) in the target list; this does\nnot affect the next item assigned to it.\n\nNames in the target list are not deleted when the loop is finished,\nbut if the sequence is empty, it will not have been assigned to at all\nby the loop. Hint: the built-in function ``range()`` returns an\niterator of integers suitable to emulate the effect of Pascal\'s ``for\ni := a to b do``; e.g., ``list(range(3))`` returns the list ``[0, 1,\n2]``.\n\nNote: There is a subtlety when the sequence is being modified by the loop\n (this can only occur for mutable sequences, i.e. lists). An\n internal counter is used to keep track of which item is used next,\n and this is incremented on each iteration. When this counter has\n reached the length of the sequence the loop terminates. This means\n that if the suite deletes the current (or a previous) item from the\n sequence, the next item will be skipped (since it gets the index of\n the current item which has already been treated). Likewise, if the\n suite inserts an item in the sequence before the current item, the\n current item will be treated again the next time through the loop.\n This can lead to nasty bugs that can be avoided by making a\n temporary copy using a slice of the whole sequence, e.g.,\n\n for x in a[:]:\n if x < 0: a.remove(x)\n', @@ -45,11 +45,11 @@ 'integers': '\nInteger literals\n****************\n\nInteger literals are described by the following lexical definitions:\n\n integer ::= decimalinteger | octinteger | hexinteger | bininteger\n decimalinteger ::= nonzerodigit digit* | "0"+\n nonzerodigit ::= "1"..."9"\n digit ::= "0"..."9"\n octinteger ::= "0" ("o" | "O") octdigit+\n hexinteger ::= "0" ("x" | "X") hexdigit+\n bininteger ::= "0" ("b" | "B") bindigit+\n octdigit ::= "0"..."7"\n hexdigit ::= digit | "a"..."f" | "A"..."F"\n bindigit ::= "0" | "1"\n\nThere is no limit for the length of integer literals apart from what\ncan be stored in available memory.\n\nNote that leading zeros in a non-zero decimal number are not allowed.\nThis is for disambiguation with C-style octal literals, which Python\nused before version 3.0.\n\nSome examples of integer literals:\n\n 7 2147483647 0o177 0b100110111\n 3 79228162514264337593543950336 0o377 0x100000000\n 79228162514264337593543950336 0xdeadbeef\n', 'lambda': '\nLambdas\n*******\n\n lambda_form ::= "lambda" [parameter_list]: expression\n lambda_form_nocond ::= "lambda" [parameter_list]: expression_nocond\n\nLambda forms (lambda expressions) have the same syntactic position as\nexpressions. They are a shorthand to create anonymous functions; the\nexpression ``lambda arguments: expression`` yields a function object.\nThe unnamed object behaves like a function object defined with\n\n def (arguments):\n return expression\n\nSee section *Function definitions* for the syntax of parameter lists.\nNote that functions created with lambda forms cannot contain\nstatements or annotations.\n', 'lists': '\nList displays\n*************\n\nA list display is a possibly empty series of expressions enclosed in\nsquare brackets:\n\n list_display ::= "[" [expression_list | comprehension] "]"\n\nA list display yields a new list object, the contents being specified\nby either a list of expressions or a comprehension. When a comma-\nseparated list of expressions is supplied, its elements are evaluated\nfrom left to right and placed into the list object in that order.\nWhen a comprehension is supplied, the list is constructed from the\nelements resulting from the comprehension.\n', - 'naming': "\nNaming and binding\n******************\n\n*Names* refer to objects. Names are introduced by name binding\noperations. Each occurrence of a name in the program text refers to\nthe *binding* of that name established in the innermost function block\ncontaining the use.\n\nA *block* is a piece of Python program text that is executed as a\nunit. The following are blocks: a module, a function body, and a class\ndefinition. Each command typed interactively is a block. A script\nfile (a file given as standard input to the interpreter or specified\non the interpreter command line the first argument) is a code block.\nA script command (a command specified on the interpreter command line\nwith the '**-c**' option) is a code block. The string argument passed\nto the built-in functions ``eval()`` and ``exec()`` is a code block.\n\nA code block is executed in an *execution frame*. A frame contains\nsome administrative information (used for debugging) and determines\nwhere and how execution continues after the code block's execution has\ncompleted.\n\nA *scope* defines the visibility of a name within a block. If a local\nvariable is defined in a block, its scope includes that block. If the\ndefinition occurs in a function block, the scope extends to any blocks\ncontained within the defining one, unless a contained block introduces\na different binding for the name. The scope of names defined in a\nclass block is limited to the class block; it does not extend to the\ncode blocks of methods -- this includes comprehensions and generator\nexpressions since they are implemented using a function scope. This\nmeans that the following will fail:\n\n class A:\n a = 42\n b = list(a + i for i in range(10))\n\nWhen a name is used in a code block, it is resolved using the nearest\nenclosing scope. The set of all such scopes visible to a code block\nis called the block's *environment*.\n\nIf a name is bound in a block, it is a local variable of that block,\nunless declared as ``nonlocal``. If a name is bound at the module\nlevel, it is a global variable. (The variables of the module code\nblock are local and global.) If a variable is used in a code block\nbut not defined there, it is a *free variable*.\n\nWhen a name is not found at all, a ``NameError`` exception is raised.\nIf the name refers to a local variable that has not been bound, a\n``UnboundLocalError`` exception is raised. ``UnboundLocalError`` is a\nsubclass of ``NameError``.\n\nThe following constructs bind names: formal parameters to functions,\n``import`` statements, class and function definitions (these bind the\nclass or function name in the defining block), and targets that are\nidentifiers if occurring in an assignment, ``for`` loop header, or\nafter ``as`` in a ``with`` statement or ``except`` clause. The\n``import`` statement of the form ``from ... import *`` binds all names\ndefined in the imported module, except those beginning with an\nunderscore. This form may only be used at the module level.\n\nA target occurring in a ``del`` statement is also considered bound for\nthis purpose (though the actual semantics are to unbind the name). It\nis illegal to unbind a name that is referenced by an enclosing scope;\nthe compiler will report a ``SyntaxError``.\n\nEach assignment or import statement occurs within a block defined by a\nclass or function definition or at the module level (the top-level\ncode block).\n\nIf a name binding operation occurs anywhere within a code block, all\nuses of the name within the block are treated as references to the\ncurrent block. This can lead to errors when a name is used within a\nblock before it is bound. This rule is subtle. Python lacks\ndeclarations and allows name binding operations to occur anywhere\nwithin a code block. The local variables of a code block can be\ndetermined by scanning the entire text of the block for name binding\noperations.\n\nIf the ``global`` statement occurs within a block, all uses of the\nname specified in the statement refer to the binding of that name in\nthe top-level namespace. Names are resolved in the top-level\nnamespace by searching the global namespace, i.e. the namespace of the\nmodule containing the code block, and the builtins namespace, the\nnamespace of the module ``builtins``. The global namespace is\nsearched first. If the name is not found there, the builtins\nnamespace is searched. The global statement must precede all uses of\nthe name.\n\nThe builtins namespace associated with the execution of a code block\nis actually found by looking up the name ``__builtins__`` in its\nglobal namespace; this should be a dictionary or a module (in the\nlatter case the module's dictionary is used). By default, when in the\n``__main__`` module, ``__builtins__`` is the built-in module\n``builtins``; when in any other module, ``__builtins__`` is an alias\nfor the dictionary of the ``builtins`` module itself.\n``__builtins__`` can be set to a user-created dictionary to create a\nweak form of restricted execution.\n\n**CPython implementation detail:** Users should not touch\n``__builtins__``; it is strictly an implementation detail. Users\nwanting to override values in the builtins namespace should ``import``\nthe ``builtins`` module and modify its attributes appropriately.\n\nThe namespace for a module is automatically created the first time a\nmodule is imported. The main module for a script is always called\n``__main__``.\n\nThe ``global`` statement has the same scope as a name binding\noperation in the same block. If the nearest enclosing scope for a\nfree variable contains a global statement, the free variable is\ntreated as a global.\n\nA class definition is an executable statement that may use and define\nnames. These references follow the normal rules for name resolution.\nThe namespace of the class definition becomes the attribute dictionary\nof the class. Names defined at the class scope are not visible in\nmethods.\n\n\nInteraction with dynamic features\n=================================\n\nThere are several cases where Python statements are illegal when used\nin conjunction with nested scopes that contain free variables.\n\nIf a variable is referenced in an enclosing scope, it is illegal to\ndelete the name. An error will be reported at compile time.\n\nIf the wild card form of import --- ``import *`` --- is used in a\nfunction and the function contains or is a nested block with free\nvariables, the compiler will raise a ``SyntaxError``.\n\nThe ``eval()`` and ``exec()`` functions do not have access to the full\nenvironment for resolving names. Names may be resolved in the local\nand global namespaces of the caller. Free variables are not resolved\nin the nearest enclosing namespace, but in the global namespace. [1]\nThe ``exec()`` and ``eval()`` functions have optional arguments to\noverride the global and local namespace. If only one namespace is\nspecified, it is used for both.\n", - 'nonlocal': '\nThe ``nonlocal`` statement\n**************************\n\n nonlocal_stmt ::= "nonlocal" identifier ("," identifier)*\n\nThe ``nonlocal`` statement causes the listed identifiers to refer to\npreviously bound variables in the nearest enclosing scope. This is\nimportant because the default behavior for binding is to search the\nlocal namespace first. The statement allows encapsulated code to\nrebind variables outside of the local scope besides the global\n(module) scope.\n\nNames listed in a ``nonlocal`` statement, unlike to those listed in a\n``global`` statement, must refer to pre-existing bindings in an\nenclosing scope (the scope in which a new binding should be created\ncannot be determined unambiguously).\n\nNames listed in a ``nonlocal`` statement must not collide with pre-\nexisting bindings in the local scope.\n\nSee also:\n\n **PEP 3104** - Access to Names in Outer Scopes\n The specification for the ``nonlocal`` statement.\n\n-[ Footnotes ]-\n\n[1] It may occur within an ``except`` or ``else`` clause. The\n restriction on occurring in the ``try`` clause is implementor\'s\n laziness and will eventually be lifted.\n', + 'naming': "\nNaming and binding\n******************\n\n*Names* refer to objects. Names are introduced by name binding\noperations. Each occurrence of a name in the program text refers to\nthe *binding* of that name established in the innermost function block\ncontaining the use.\n\nA *block* is a piece of Python program text that is executed as a\nunit. The following are blocks: a module, a function body, and a class\ndefinition. Each command typed interactively is a block. A script\nfile (a file given as standard input to the interpreter or specified\non the interpreter command line the first argument) is a code block.\nA script command (a command specified on the interpreter command line\nwith the '**-c**' option) is a code block. The string argument passed\nto the built-in functions ``eval()`` and ``exec()`` is a code block.\n\nA code block is executed in an *execution frame*. A frame contains\nsome administrative information (used for debugging) and determines\nwhere and how execution continues after the code block's execution has\ncompleted.\n\nA *scope* defines the visibility of a name within a block. If a local\nvariable is defined in a block, its scope includes that block. If the\ndefinition occurs in a function block, the scope extends to any blocks\ncontained within the defining one, unless a contained block introduces\na different binding for the name. The scope of names defined in a\nclass block is limited to the class block; it does not extend to the\ncode blocks of methods -- this includes comprehensions and generator\nexpressions since they are implemented using a function scope. This\nmeans that the following will fail:\n\n class A:\n a = 42\n b = list(a + i for i in range(10))\n\nWhen a name is used in a code block, it is resolved using the nearest\nenclosing scope. The set of all such scopes visible to a code block\nis called the block's *environment*.\n\nIf a name is bound in a block, it is a local variable of that block,\nunless declared as ``nonlocal``. If a name is bound at the module\nlevel, it is a global variable. (The variables of the module code\nblock are local and global.) If a variable is used in a code block\nbut not defined there, it is a *free variable*.\n\nWhen a name is not found at all, a ``NameError`` exception is raised.\nIf the name refers to a local variable that has not been bound, a\n``UnboundLocalError`` exception is raised. ``UnboundLocalError`` is a\nsubclass of ``NameError``.\n\nThe following constructs bind names: formal parameters to functions,\n``import`` statements, class and function definitions (these bind the\nclass or function name in the defining block), and targets that are\nidentifiers if occurring in an assignment, ``for`` loop header, or\nafter ``as`` in a ``with`` statement or ``except`` clause. The\n``import`` statement of the form ``from ... import *`` binds all names\ndefined in the imported module, except those beginning with an\nunderscore. This form may only be used at the module level.\n\nA target occurring in a ``del`` statement is also considered bound for\nthis purpose (though the actual semantics are to unbind the name).\n\nEach assignment or import statement occurs within a block defined by a\nclass or function definition or at the module level (the top-level\ncode block).\n\nIf a name binding operation occurs anywhere within a code block, all\nuses of the name within the block are treated as references to the\ncurrent block. This can lead to errors when a name is used within a\nblock before it is bound. This rule is subtle. Python lacks\ndeclarations and allows name binding operations to occur anywhere\nwithin a code block. The local variables of a code block can be\ndetermined by scanning the entire text of the block for name binding\noperations.\n\nIf the ``global`` statement occurs within a block, all uses of the\nname specified in the statement refer to the binding of that name in\nthe top-level namespace. Names are resolved in the top-level\nnamespace by searching the global namespace, i.e. the namespace of the\nmodule containing the code block, and the builtins namespace, the\nnamespace of the module ``builtins``. The global namespace is\nsearched first. If the name is not found there, the builtins\nnamespace is searched. The global statement must precede all uses of\nthe name.\n\nThe builtins namespace associated with the execution of a code block\nis actually found by looking up the name ``__builtins__`` in its\nglobal namespace; this should be a dictionary or a module (in the\nlatter case the module's dictionary is used). By default, when in the\n``__main__`` module, ``__builtins__`` is the built-in module\n``builtins``; when in any other module, ``__builtins__`` is an alias\nfor the dictionary of the ``builtins`` module itself.\n``__builtins__`` can be set to a user-created dictionary to create a\nweak form of restricted execution.\n\n**CPython implementation detail:** Users should not touch\n``__builtins__``; it is strictly an implementation detail. Users\nwanting to override values in the builtins namespace should ``import``\nthe ``builtins`` module and modify its attributes appropriately.\n\nThe namespace for a module is automatically created the first time a\nmodule is imported. The main module for a script is always called\n``__main__``.\n\nThe ``global`` statement has the same scope as a name binding\noperation in the same block. If the nearest enclosing scope for a\nfree variable contains a global statement, the free variable is\ntreated as a global.\n\nA class definition is an executable statement that may use and define\nnames. These references follow the normal rules for name resolution.\nThe namespace of the class definition becomes the attribute dictionary\nof the class. Names defined at the class scope are not visible in\nmethods.\n\n\nInteraction with dynamic features\n=================================\n\nThere are several cases where Python statements are illegal when used\nin conjunction with nested scopes that contain free variables.\n\nIf a variable is referenced in an enclosing scope, it is illegal to\ndelete the name. An error will be reported at compile time.\n\nIf the wild card form of import --- ``import *`` --- is used in a\nfunction and the function contains or is a nested block with free\nvariables, the compiler will raise a ``SyntaxError``.\n\nThe ``eval()`` and ``exec()`` functions do not have access to the full\nenvironment for resolving names. Names may be resolved in the local\nand global namespaces of the caller. Free variables are not resolved\nin the nearest enclosing namespace, but in the global namespace. [1]\nThe ``exec()`` and ``eval()`` functions have optional arguments to\noverride the global and local namespace. If only one namespace is\nspecified, it is used for both.\n", + 'nonlocal': '\nThe ``nonlocal`` statement\n**************************\n\n nonlocal_stmt ::= "nonlocal" identifier ("," identifier)*\n\nThe ``nonlocal`` statement causes the listed identifiers to refer to\npreviously bound variables in the nearest enclosing scope. This is\nimportant because the default behavior for binding is to search the\nlocal namespace first. The statement allows encapsulated code to\nrebind variables outside of the local scope besides the global\n(module) scope.\n\nNames listed in a ``nonlocal`` statement, unlike to those listed in a\n``global`` statement, must refer to pre-existing bindings in an\nenclosing scope (the scope in which a new binding should be created\ncannot be determined unambiguously).\n\nNames listed in a ``nonlocal`` statement must not collide with pre-\nexisting bindings in the local scope.\n\nSee also:\n\n **PEP 3104** - Access to Names in Outer Scopes\n The specification for the ``nonlocal`` statement.\n', 'numbers': "\nNumeric literals\n****************\n\nThere are three types of numeric literals: integers, floating point\nnumbers, and imaginary numbers. There are no complex literals\n(complex numbers can be formed by adding a real number and an\nimaginary number).\n\nNote that numeric literals do not include a sign; a phrase like ``-1``\nis actually an expression composed of the unary operator '``-``' and\nthe literal ``1``.\n", 'numeric-types': "\nEmulating numeric types\n***********************\n\nThe following methods can be defined to emulate numeric objects.\nMethods corresponding to operations that are not supported by the\nparticular kind of number implemented (e.g., bitwise operations for\nnon-integral numbers) should be left undefined.\n\nobject.__add__(self, other)\nobject.__sub__(self, other)\nobject.__mul__(self, other)\nobject.__truediv__(self, other)\nobject.__floordiv__(self, other)\nobject.__mod__(self, other)\nobject.__divmod__(self, other)\nobject.__pow__(self, other[, modulo])\nobject.__lshift__(self, other)\nobject.__rshift__(self, other)\nobject.__and__(self, other)\nobject.__xor__(self, other)\nobject.__or__(self, other)\n\n These methods are called to implement the binary arithmetic\n operations (``+``, ``-``, ``*``, ``/``, ``//``, ``%``,\n ``divmod()``, ``pow()``, ``**``, ``<<``, ``>>``, ``&``, ``^``,\n ``|``). For instance, to evaluate the expression ``x + y``, where\n *x* is an instance of a class that has an ``__add__()`` method,\n ``x.__add__(y)`` is called. The ``__divmod__()`` method should be\n the equivalent to using ``__floordiv__()`` and ``__mod__()``; it\n should not be related to ``__truediv__()``. Note that\n ``__pow__()`` should be defined to accept an optional third\n argument if the ternary version of the built-in ``pow()`` function\n is to be supported.\n\n If one of those methods does not support the operation with the\n supplied arguments, it should return ``NotImplemented``.\n\nobject.__radd__(self, other)\nobject.__rsub__(self, other)\nobject.__rmul__(self, other)\nobject.__rtruediv__(self, other)\nobject.__rfloordiv__(self, other)\nobject.__rmod__(self, other)\nobject.__rdivmod__(self, other)\nobject.__rpow__(self, other)\nobject.__rlshift__(self, other)\nobject.__rrshift__(self, other)\nobject.__rand__(self, other)\nobject.__rxor__(self, other)\nobject.__ror__(self, other)\n\n These methods are called to implement the binary arithmetic\n operations (``+``, ``-``, ``*``, ``/``, ``//``, ``%``,\n ``divmod()``, ``pow()``, ``**``, ``<<``, ``>>``, ``&``, ``^``,\n ``|``) with reflected (swapped) operands. These functions are only\n called if the left operand does not support the corresponding\n operation and the operands are of different types. [2] For\n instance, to evaluate the expression ``x - y``, where *y* is an\n instance of a class that has an ``__rsub__()`` method,\n ``y.__rsub__(x)`` is called if ``x.__sub__(y)`` returns\n *NotImplemented*.\n\n Note that ternary ``pow()`` will not try calling ``__rpow__()``\n (the coercion rules would become too complicated).\n\n Note: If the right operand's type is a subclass of the left operand's\n type and that subclass provides the reflected method for the\n operation, this method will be called before the left operand's\n non-reflected method. This behavior allows subclasses to\n override their ancestors' operations.\n\nobject.__iadd__(self, other)\nobject.__isub__(self, other)\nobject.__imul__(self, other)\nobject.__itruediv__(self, other)\nobject.__ifloordiv__(self, other)\nobject.__imod__(self, other)\nobject.__ipow__(self, other[, modulo])\nobject.__ilshift__(self, other)\nobject.__irshift__(self, other)\nobject.__iand__(self, other)\nobject.__ixor__(self, other)\nobject.__ior__(self, other)\n\n These methods are called to implement the augmented arithmetic\n assignments (``+=``, ``-=``, ``*=``, ``/=``, ``//=``, ``%=``,\n ``**=``, ``<<=``, ``>>=``, ``&=``, ``^=``, ``|=``). These methods\n should attempt to do the operation in-place (modifying *self*) and\n return the result (which could be, but does not have to be,\n *self*). If a specific method is not defined, the augmented\n assignment falls back to the normal methods. For instance, to\n execute the statement ``x += y``, where *x* is an instance of a\n class that has an ``__iadd__()`` method, ``x.__iadd__(y)`` is\n called. If *x* is an instance of a class that does not define a\n ``__iadd__()`` method, ``x.__add__(y)`` and ``y.__radd__(x)`` are\n considered, as with the evaluation of ``x + y``.\n\nobject.__neg__(self)\nobject.__pos__(self)\nobject.__abs__(self)\nobject.__invert__(self)\n\n Called to implement the unary arithmetic operations (``-``, ``+``,\n ``abs()`` and ``~``).\n\nobject.__complex__(self)\nobject.__int__(self)\nobject.__float__(self)\nobject.__round__(self[, n])\n\n Called to implement the built-in functions ``complex()``,\n ``int()``, ``float()`` and ``round()``. Should return a value of\n the appropriate type.\n\nobject.__index__(self)\n\n Called to implement ``operator.index()``. Also called whenever\n Python needs an integer object (such as in slicing, or in the\n built-in ``bin()``, ``hex()`` and ``oct()`` functions). Must return\n an integer.\n", - 'objects': '\nObjects, values and types\n*************************\n\n*Objects* are Python\'s abstraction for data. All data in a Python\nprogram is represented by objects or by relations between objects. (In\na sense, and in conformance to Von Neumann\'s model of a "stored\nprogram computer," code is also represented by objects.)\n\nEvery object has an identity, a type and a value. An object\'s\n*identity* never changes once it has been created; you may think of it\nas the object\'s address in memory. The \'``is``\' operator compares the\nidentity of two objects; the ``id()`` function returns an integer\nrepresenting its identity (currently implemented as its address). An\nobject\'s *type* is also unchangeable. [1] An object\'s type determines\nthe operations that the object supports (e.g., "does it have a\nlength?") and also defines the possible values for objects of that\ntype. The ``type()`` function returns an object\'s type (which is an\nobject itself). The *value* of some objects can change. Objects\nwhose value can change are said to be *mutable*; objects whose value\nis unchangeable once they are created are called *immutable*. (The\nvalue of an immutable container object that contains a reference to a\nmutable object can change when the latter\'s value is changed; however\nthe container is still considered immutable, because the collection of\nobjects it contains cannot be changed. So, immutability is not\nstrictly the same as having an unchangeable value, it is more subtle.)\nAn object\'s mutability is determined by its type; for instance,\nnumbers, strings and tuples are immutable, while dictionaries and\nlists are mutable.\n\nObjects are never explicitly destroyed; however, when they become\nunreachable they may be garbage-collected. An implementation is\nallowed to postpone garbage collection or omit it altogether --- it is\na matter of implementation quality how garbage collection is\nimplemented, as long as no objects are collected that are still\nreachable.\n\n**CPython implementation detail:** CPython currently uses a reference-\ncounting scheme with (optional) delayed detection of cyclically linked\ngarbage, which collects most objects as soon as they become\nunreachable, but is not guaranteed to collect garbage containing\ncircular references. See the documentation of the ``gc`` module for\ninformation on controlling the collection of cyclic garbage. Other\nimplementations act differently and CPython may change.\n\nNote that the use of the implementation\'s tracing or debugging\nfacilities may keep objects alive that would normally be collectable.\nAlso note that catching an exception with a \'``try``...``except``\'\nstatement may keep objects alive.\n\nSome objects contain references to "external" resources such as open\nfiles or windows. It is understood that these resources are freed\nwhen the object is garbage-collected, but since garbage collection is\nnot guaranteed to happen, such objects also provide an explicit way to\nrelease the external resource, usually a ``close()`` method. Programs\nare strongly recommended to explicitly close such objects. The\n\'``try``...``finally``\' statement and the \'``with``\' statement provide\nconvenient ways to do this.\n\nSome objects contain references to other objects; these are called\n*containers*. Examples of containers are tuples, lists and\ndictionaries. The references are part of a container\'s value. In\nmost cases, when we talk about the value of a container, we imply the\nvalues, not the identities of the contained objects; however, when we\ntalk about the mutability of a container, only the identities of the\nimmediately contained objects are implied. So, if an immutable\ncontainer (like a tuple) contains a reference to a mutable object, its\nvalue changes if that mutable object is changed.\n\nTypes affect almost all aspects of object behavior. Even the\nimportance of object identity is affected in some sense: for immutable\ntypes, operations that compute new values may actually return a\nreference to any existing object with the same type and value, while\nfor mutable objects this is not allowed. E.g., after ``a = 1; b =\n1``, ``a`` and ``b`` may or may not refer to the same object with the\nvalue one, depending on the implementation, but after ``c = []; d =\n[]``, ``c`` and ``d`` are guaranteed to refer to two different,\nunique, newly created empty lists. (Note that ``c = d = []`` assigns\nthe same object to both ``c`` and ``d``.)\n', + 'objects': '\nObjects, values and types\n*************************\n\n*Objects* are Python\'s abstraction for data. All data in a Python\nprogram is represented by objects or by relations between objects. (In\na sense, and in conformance to Von Neumann\'s model of a "stored\nprogram computer," code is also represented by objects.)\n\nEvery object has an identity, a type and a value. An object\'s\n*identity* never changes once it has been created; you may think of it\nas the object\'s address in memory. The \'``is``\' operator compares the\nidentity of two objects; the ``id()`` function returns an integer\nrepresenting its identity (currently implemented as its address). An\nobject\'s *type* is also unchangeable. [1] An object\'s type determines\nthe operations that the object supports (e.g., "does it have a\nlength?") and also defines the possible values for objects of that\ntype. The ``type()`` function returns an object\'s type (which is an\nobject itself). The *value* of some objects can change. Objects\nwhose value can change are said to be *mutable*; objects whose value\nis unchangeable once they are created are called *immutable*. (The\nvalue of an immutable container object that contains a reference to a\nmutable object can change when the latter\'s value is changed; however\nthe container is still considered immutable, because the collection of\nobjects it contains cannot be changed. So, immutability is not\nstrictly the same as having an unchangeable value, it is more subtle.)\nAn object\'s mutability is determined by its type; for instance,\nnumbers, strings and tuples are immutable, while dictionaries and\nlists are mutable.\n\nObjects are never explicitly destroyed; however, when they become\nunreachable they may be garbage-collected. An implementation is\nallowed to postpone garbage collection or omit it altogether --- it is\na matter of implementation quality how garbage collection is\nimplemented, as long as no objects are collected that are still\nreachable.\n\n**CPython implementation detail:** CPython currently uses a reference-\ncounting scheme with (optional) delayed detection of cyclically linked\ngarbage, which collects most objects as soon as they become\nunreachable, but is not guaranteed to collect garbage containing\ncircular references. See the documentation of the ``gc`` module for\ninformation on controlling the collection of cyclic garbage. Other\nimplementations act differently and CPython may change. Do not depend\non immediate finalization of objects when they become unreachable (ex:\nalways close files).\n\nNote that the use of the implementation\'s tracing or debugging\nfacilities may keep objects alive that would normally be collectable.\nAlso note that catching an exception with a \'``try``...``except``\'\nstatement may keep objects alive.\n\nSome objects contain references to "external" resources such as open\nfiles or windows. It is understood that these resources are freed\nwhen the object is garbage-collected, but since garbage collection is\nnot guaranteed to happen, such objects also provide an explicit way to\nrelease the external resource, usually a ``close()`` method. Programs\nare strongly recommended to explicitly close such objects. The\n\'``try``...``finally``\' statement and the \'``with``\' statement provide\nconvenient ways to do this.\n\nSome objects contain references to other objects; these are called\n*containers*. Examples of containers are tuples, lists and\ndictionaries. The references are part of a container\'s value. In\nmost cases, when we talk about the value of a container, we imply the\nvalues, not the identities of the contained objects; however, when we\ntalk about the mutability of a container, only the identities of the\nimmediately contained objects are implied. So, if an immutable\ncontainer (like a tuple) contains a reference to a mutable object, its\nvalue changes if that mutable object is changed.\n\nTypes affect almost all aspects of object behavior. Even the\nimportance of object identity is affected in some sense: for immutable\ntypes, operations that compute new values may actually return a\nreference to any existing object with the same type and value, while\nfor mutable objects this is not allowed. E.g., after ``a = 1; b =\n1``, ``a`` and ``b`` may or may not refer to the same object with the\nvalue one, depending on the implementation, but after ``c = []; d =\n[]``, ``c`` and ``d`` are guaranteed to refer to two different,\nunique, newly created empty lists. (Note that ``c = d = []`` assigns\nthe same object to both ``c`` and ``d``.)\n', 'operator-summary': '\nSummary\n*******\n\nThe following table summarizes the operator precedences in Python,\nfrom lowest precedence (least binding) to highest precedence (most\nbinding). Operators in the same box have the same precedence. Unless\nthe syntax is explicitly given, operators are binary. Operators in\nthe same box group left to right (except for comparisons, including\ntests, which all have the same precedence and chain from left to right\n--- see section *Comparisons* --- and exponentiation, which groups\nfrom right to left).\n\n+-------------------------------------------------+---------------------------------------+\n| Operator | Description |\n+=================================================+=======================================+\n| ``lambda`` | Lambda expression |\n+-------------------------------------------------+---------------------------------------+\n| ``if`` -- ``else`` | Conditional expression |\n+-------------------------------------------------+---------------------------------------+\n| ``or`` | Boolean OR |\n+-------------------------------------------------+---------------------------------------+\n| ``and`` | Boolean AND |\n+-------------------------------------------------+---------------------------------------+\n| ``not`` *x* | Boolean NOT |\n+-------------------------------------------------+---------------------------------------+\n| ``in``, ``not`` ``in``, ``is``, ``is not``, | Comparisons, including membership |\n| ``<``, ``<=``, ``>``, ``>=``, ``!=``, ``==`` | tests and identity tests, |\n+-------------------------------------------------+---------------------------------------+\n| ``|`` | Bitwise OR |\n+-------------------------------------------------+---------------------------------------+\n| ``^`` | Bitwise XOR |\n+-------------------------------------------------+---------------------------------------+\n| ``&`` | Bitwise AND |\n+-------------------------------------------------+---------------------------------------+\n| ``<<``, ``>>`` | Shifts |\n+-------------------------------------------------+---------------------------------------+\n| ``+``, ``-`` | Addition and subtraction |\n+-------------------------------------------------+---------------------------------------+\n| ``*``, ``/``, ``//``, ``%`` | Multiplication, division, remainder |\n| | [5] |\n+-------------------------------------------------+---------------------------------------+\n| ``+x``, ``-x``, ``~x`` | Positive, negative, bitwise NOT |\n+-------------------------------------------------+---------------------------------------+\n| ``**`` | Exponentiation [6] |\n+-------------------------------------------------+---------------------------------------+\n| ``x[index]``, ``x[index:index]``, | Subscription, slicing, call, |\n| ``x(arguments...)``, ``x.attribute`` | attribute reference |\n+-------------------------------------------------+---------------------------------------+\n| ``(expressions...)``, ``[expressions...]``, | Binding or tuple display, list |\n| ``{key:datum...}``, ``{expressions...}`` | display, dictionary display, set |\n| | display |\n+-------------------------------------------------+---------------------------------------+\n\n-[ Footnotes ]-\n\n[1] While ``abs(x%y) < abs(y)`` is true mathematically, for floats it\n may not be true numerically due to roundoff. For example, and\n assuming a platform on which a Python float is an IEEE 754 double-\n precision number, in order that ``-1e-100 % 1e100`` have the same\n sign as ``1e100``, the computed result is ``-1e-100 + 1e100``,\n which is numerically exactly equal to ``1e100``. The function\n ``math.fmod()`` returns a result whose sign matches the sign of\n the first argument instead, and so returns ``-1e-100`` in this\n case. Which approach is more appropriate depends on the\n application.\n\n[2] If x is very close to an exact integer multiple of y, it\'s\n possible for ``x//y`` to be one larger than ``(x-x%y)//y`` due to\n rounding. In such cases, Python returns the latter result, in\n order to preserve that ``divmod(x,y)[0] * y + x % y`` be very\n close to ``x``.\n\n[3] While comparisons between strings make sense at the byte level,\n they may be counter-intuitive to users. For example, the strings\n ``"\\u00C7"`` and ``"\\u0327\\u0043"`` compare differently, even\n though they both represent the same unicode character (LATIN\n CAPITAL LETTER C WITH CEDILLA). To compare strings in a human\n recognizable way, compare using ``unicodedata.normalize()``.\n\n[4] Due to automatic garbage-collection, free lists, and the dynamic\n nature of descriptors, you may notice seemingly unusual behaviour\n in certain uses of the ``is`` operator, like those involving\n comparisons between instance methods, or constants. Check their\n documentation for more info.\n\n[5] The ``%`` operator is also used for string formatting; the same\n precedence applies.\n\n[6] The power operator ``**`` binds less tightly than an arithmetic or\n bitwise unary operator on its right, that is, ``2**-1`` is\n ``0.5``.\n', 'pass': '\nThe ``pass`` statement\n**********************\n\n pass_stmt ::= "pass"\n\n``pass`` is a null operation --- when it is executed, nothing happens.\nIt is useful as a placeholder when a statement is required\nsyntactically, but no code needs to be executed, for example:\n\n def f(arg): pass # a function that does nothing (yet)\n\n class C: pass # a class with no methods (yet)\n', 'power': '\nThe power operator\n******************\n\nThe power operator binds more tightly than unary operators on its\nleft; it binds less tightly than unary operators on its right. The\nsyntax is:\n\n power ::= primary ["**" u_expr]\n\nThus, in an unparenthesized sequence of power and unary operators, the\noperators are evaluated from right to left (this does not constrain\nthe evaluation order for the operands): ``-1**2`` results in ``-1``.\n\nThe power operator has the same semantics as the built-in ``pow()``\nfunction, when called with two arguments: it yields its left argument\nraised to the power of its right argument. The numeric arguments are\nfirst converted to a common type, and the result is of that type.\n\nFor int operands, the result has the same type as the operands unless\nthe second argument is negative; in that case, all arguments are\nconverted to float and a float result is delivered. For example,\n``10**2`` returns ``100``, but ``10**-2`` returns ``0.01``.\n\nRaising ``0.0`` to a negative power results in a\n``ZeroDivisionError``. Raising a negative number to a fractional power\nresults in a ``complex`` number. (In earlier versions it raised a\n``ValueError``.)\n', @@ -59,7 +59,7 @@ 'shifting': '\nShifting operations\n*******************\n\nThe shifting operations have lower priority than the arithmetic\noperations:\n\n shift_expr ::= a_expr | shift_expr ( "<<" | ">>" ) a_expr\n\nThese operators accept integers as arguments. They shift the first\nargument to the left or right by the number of bits given by the\nsecond argument.\n\nA right shift by *n* bits is defined as division by ``pow(2,n)``. A\nleft shift by *n* bits is defined as multiplication with ``pow(2,n)``.\n\nNote: In the current implementation, the right-hand operand is required to\n be at most ``sys.maxsize``. If the right-hand operand is larger\n than ``sys.maxsize`` an ``OverflowError`` exception is raised.\n', 'slicings': '\nSlicings\n********\n\nA slicing selects a range of items in a sequence object (e.g., a\nstring, tuple or list). Slicings may be used as expressions or as\ntargets in assignment or ``del`` statements. The syntax for a\nslicing:\n\n slicing ::= primary "[" slice_list "]"\n slice_list ::= slice_item ("," slice_item)* [","]\n slice_item ::= expression | proper_slice\n proper_slice ::= [lower_bound] ":" [upper_bound] [ ":" [stride] ]\n lower_bound ::= expression\n upper_bound ::= expression\n stride ::= expression\n\nThere is ambiguity in the formal syntax here: anything that looks like\nan expression list also looks like a slice list, so any subscription\ncan be interpreted as a slicing. Rather than further complicating the\nsyntax, this is disambiguated by defining that in this case the\ninterpretation as a subscription takes priority over the\ninterpretation as a slicing (this is the case if the slice list\ncontains no proper slice).\n\nThe semantics for a slicing are as follows. The primary must evaluate\nto a mapping object, and it is indexed (using the same\n``__getitem__()`` method as normal subscription) with a key that is\nconstructed from the slice list, as follows. If the slice list\ncontains at least one comma, the key is a tuple containing the\nconversion of the slice items; otherwise, the conversion of the lone\nslice item is the key. The conversion of a slice item that is an\nexpression is that expression. The conversion of a proper slice is a\nslice object (see section *The standard type hierarchy*) whose\n``start``, ``stop`` and ``step`` attributes are the values of the\nexpressions given as lower bound, upper bound and stride,\nrespectively, substituting ``None`` for missing expressions.\n', 'specialattrs': "\nSpecial Attributes\n******************\n\nThe implementation adds a few special read-only attributes to several\nobject types, where they are relevant. Some of these are not reported\nby the ``dir()`` built-in function.\n\nobject.__dict__\n\n A dictionary or other mapping object used to store an object's\n (writable) attributes.\n\ninstance.__class__\n\n The class to which a class instance belongs.\n\nclass.__bases__\n\n The tuple of base classes of a class object.\n\nclass.__name__\n\n The name of the class or type.\n\nThe following attributes are only supported by *new-style class*es.\n\nclass.__mro__\n\n This attribute is a tuple of classes that are considered when\n looking for base classes during method resolution.\n\nclass.mro()\n\n This method can be overridden by a metaclass to customize the\n method resolution order for its instances. It is called at class\n instantiation, and its result is stored in ``__mro__``.\n\nclass.__subclasses__()\n\n Each new-style class keeps a list of weak references to its\n immediate subclasses. This method returns a list of all those\n references still alive. Example:\n\n >>> int.__subclasses__()\n []\n\n-[ Footnotes ]-\n\n[1] Additional information on these special methods may be found in\n the Python Reference Manual (*Basic customization*).\n\n[2] As a consequence, the list ``[1, 2]`` is considered equal to\n ``[1.0, 2.0]``, and similarly for tuples.\n\n[3] They must have since the parser can't tell the type of the\n operands.\n\n[4] To format only a tuple you should therefore provide a singleton\n tuple whose only element is the tuple to be formatted.\n", - 'specialnames': '\nSpecial method names\n********************\n\nA class can implement certain operations that are invoked by special\nsyntax (such as arithmetic operations or subscripting and slicing) by\ndefining methods with special names. This is Python\'s approach to\n*operator overloading*, allowing classes to define their own behavior\nwith respect to language operators. For instance, if a class defines\na method named ``__getitem__()``, and ``x`` is an instance of this\nclass, then ``x[i]`` is roughly equivalent to ``type(x).__getitem__(x,\ni)``. Except where mentioned, attempts to execute an operation raise\nan exception when no appropriate method is defined (typically\n``AttributeError`` or ``TypeError``).\n\nWhen implementing a class that emulates any built-in type, it is\nimportant that the emulation only be implemented to the degree that it\nmakes sense for the object being modelled. For example, some\nsequences may work well with retrieval of individual elements, but\nextracting a slice may not make sense. (One example of this is the\n``NodeList`` interface in the W3C\'s Document Object Model.)\n\n\nBasic customization\n===================\n\nobject.__new__(cls[, ...])\n\n Called to create a new instance of class *cls*. ``__new__()`` is a\n static method (special-cased so you need not declare it as such)\n that takes the class of which an instance was requested as its\n first argument. The remaining arguments are those passed to the\n object constructor expression (the call to the class). The return\n value of ``__new__()`` should be the new object instance (usually\n an instance of *cls*).\n\n Typical implementations create a new instance of the class by\n invoking the superclass\'s ``__new__()`` method using\n ``super(currentclass, cls).__new__(cls[, ...])`` with appropriate\n arguments and then modifying the newly-created instance as\n necessary before returning it.\n\n If ``__new__()`` returns an instance of *cls*, then the new\n instance\'s ``__init__()`` method will be invoked like\n ``__init__(self[, ...])``, where *self* is the new instance and the\n remaining arguments are the same as were passed to ``__new__()``.\n\n If ``__new__()`` does not return an instance of *cls*, then the new\n instance\'s ``__init__()`` method will not be invoked.\n\n ``__new__()`` is intended mainly to allow subclasses of immutable\n types (like int, str, or tuple) to customize instance creation. It\n is also commonly overridden in custom metaclasses in order to\n customize class creation.\n\nobject.__init__(self[, ...])\n\n Called when the instance is created. The arguments are those\n passed to the class constructor expression. If a base class has an\n ``__init__()`` method, the derived class\'s ``__init__()`` method,\n if any, must explicitly call it to ensure proper initialization of\n the base class part of the instance; for example:\n ``BaseClass.__init__(self, [args...])``. As a special constraint\n on constructors, no value may be returned; doing so will cause a\n ``TypeError`` to be raised at runtime.\n\nobject.__del__(self)\n\n Called when the instance is about to be destroyed. This is also\n called a destructor. If a base class has a ``__del__()`` method,\n the derived class\'s ``__del__()`` method, if any, must explicitly\n call it to ensure proper deletion of the base class part of the\n instance. Note that it is possible (though not recommended!) for\n the ``__del__()`` method to postpone destruction of the instance by\n creating a new reference to it. It may then be called at a later\n time when this new reference is deleted. It is not guaranteed that\n ``__del__()`` methods are called for objects that still exist when\n the interpreter exits.\n\n Note: ``del x`` doesn\'t directly call ``x.__del__()`` --- the former\n decrements the reference count for ``x`` by one, and the latter\n is only called when ``x``\'s reference count reaches zero. Some\n common situations that may prevent the reference count of an\n object from going to zero include: circular references between\n objects (e.g., a doubly-linked list or a tree data structure with\n parent and child pointers); a reference to the object on the\n stack frame of a function that caught an exception (the traceback\n stored in ``sys.exc_info()[2]`` keeps the stack frame alive); or\n a reference to the object on the stack frame that raised an\n unhandled exception in interactive mode (the traceback stored in\n ``sys.last_traceback`` keeps the stack frame alive). The first\n situation can only be remedied by explicitly breaking the cycles;\n the latter two situations can be resolved by storing ``None`` in\n ``sys.last_traceback``. Circular references which are garbage are\n detected when the option cycle detector is enabled (it\'s on by\n default), but can only be cleaned up if there are no Python-\n level ``__del__()`` methods involved. Refer to the documentation\n for the ``gc`` module for more information about how\n ``__del__()`` methods are handled by the cycle detector,\n particularly the description of the ``garbage`` value.\n\n Warning: Due to the precarious circumstances under which ``__del__()``\n methods are invoked, exceptions that occur during their execution\n are ignored, and a warning is printed to ``sys.stderr`` instead.\n Also, when ``__del__()`` is invoked in response to a module being\n deleted (e.g., when execution of the program is done), other\n globals referenced by the ``__del__()`` method may already have\n been deleted or in the process of being torn down (e.g. the\n import machinery shutting down). For this reason, ``__del__()``\n methods should do the absolute minimum needed to maintain\n external invariants. Starting with version 1.5, Python\n guarantees that globals whose name begins with a single\n underscore are deleted from their module before other globals are\n deleted; if no other references to such globals exist, this may\n help in assuring that imported modules are still available at the\n time when the ``__del__()`` method is called.\n\nobject.__repr__(self)\n\n Called by the ``repr()`` built-in function to compute the\n "official" string representation of an object. If at all possible,\n this should look like a valid Python expression that could be used\n to recreate an object with the same value (given an appropriate\n environment). If this is not possible, a string of the form\n ``<...some useful description...>`` should be returned. The return\n value must be a string object. If a class defines ``__repr__()``\n but not ``__str__()``, then ``__repr__()`` is also used when an\n "informal" string representation of instances of that class is\n required.\n\n This is typically used for debugging, so it is important that the\n representation is information-rich and unambiguous.\n\nobject.__str__(self)\n\n Called by the ``str()`` built-in function and by the ``print()``\n function to compute the "informal" string representation of an\n object. This differs from ``__repr__()`` in that it does not have\n to be a valid Python expression: a more convenient or concise\n representation may be used instead. The return value must be a\n string object.\n\nobject.__format__(self, format_spec)\n\n Called by the ``format()`` built-in function (and by extension, the\n ``format()`` method of class ``str``) to produce a "formatted"\n string representation of an object. The ``format_spec`` argument is\n a string that contains a description of the formatting options\n desired. The interpretation of the ``format_spec`` argument is up\n to the type implementing ``__format__()``, however most classes\n will either delegate formatting to one of the built-in types, or\n use a similar formatting option syntax.\n\n See *Format Specification Mini-Language* for a description of the\n standard formatting syntax.\n\n The return value must be a string object.\n\nobject.__lt__(self, other)\nobject.__le__(self, other)\nobject.__eq__(self, other)\nobject.__ne__(self, other)\nobject.__gt__(self, other)\nobject.__ge__(self, other)\n\n These are the so-called "rich comparison" methods. The\n correspondence between operator symbols and method names is as\n follows: ``xy`` calls ``x.__gt__(y)``, and ``x>=y`` calls\n ``x.__ge__(y)``.\n\n A rich comparison method may return the singleton\n ``NotImplemented`` if it does not implement the operation for a\n given pair of arguments. By convention, ``False`` and ``True`` are\n returned for a successful comparison. However, these methods can\n return any value, so if the comparison operator is used in a\n Boolean context (e.g., in the condition of an ``if`` statement),\n Python will call ``bool()`` on the value to determine if the result\n is true or false.\n\n There are no implied relationships among the comparison operators.\n The truth of ``x==y`` does not imply that ``x!=y`` is false.\n Accordingly, when defining ``__eq__()``, one should also define\n ``__ne__()`` so that the operators will behave as expected. See\n the paragraph on ``__hash__()`` for some important notes on\n creating *hashable* objects which support custom comparison\n operations and are usable as dictionary keys.\n\n There are no swapped-argument versions of these methods (to be used\n when the left argument does not support the operation but the right\n argument does); rather, ``__lt__()`` and ``__gt__()`` are each\n other\'s reflection, ``__le__()`` and ``__ge__()`` are each other\'s\n reflection, and ``__eq__()`` and ``__ne__()`` are their own\n reflection.\n\n Arguments to rich comparison methods are never coerced.\n\n To automatically generate ordering operations from a single root\n operation, see ``functools.total_ordering()``.\n\nobject.__hash__(self)\n\n Called by built-in function ``hash()`` and for operations on\n members of hashed collections including ``set``, ``frozenset``, and\n ``dict``. ``__hash__()`` should return an integer. The only\n required property is that objects which compare equal have the same\n hash value; it is advised to somehow mix together (e.g. using\n exclusive or) the hash values for the components of the object that\n also play a part in comparison of objects.\n\n If a class does not define an ``__eq__()`` method it should not\n define a ``__hash__()`` operation either; if it defines\n ``__eq__()`` but not ``__hash__()``, its instances will not be\n usable as items in hashable collections. If a class defines\n mutable objects and implements an ``__eq__()`` method, it should\n not implement ``__hash__()``, since the implementation of hashable\n collections requires that a key\'s hash value is immutable (if the\n object\'s hash value changes, it will be in the wrong hash bucket).\n\n User-defined classes have ``__eq__()`` and ``__hash__()`` methods\n by default; with them, all objects compare unequal (except with\n themselves) and ``x.__hash__()`` returns ``id(x)``.\n\n Classes which inherit a ``__hash__()`` method from a parent class\n but change the meaning of ``__eq__()`` such that the hash value\n returned is no longer appropriate (e.g. by switching to a value-\n based concept of equality instead of the default identity based\n equality) can explicitly flag themselves as being unhashable by\n setting ``__hash__ = None`` in the class definition. Doing so means\n that not only will instances of the class raise an appropriate\n ``TypeError`` when a program attempts to retrieve their hash value,\n but they will also be correctly identified as unhashable when\n checking ``isinstance(obj, collections.Hashable)`` (unlike classes\n which define their own ``__hash__()`` to explicitly raise\n ``TypeError``).\n\n If a class that overrides ``__eq__()`` needs to retain the\n implementation of ``__hash__()`` from a parent class, the\n interpreter must be told this explicitly by setting ``__hash__ =\n .__hash__``. Otherwise the inheritance of\n ``__hash__()`` will be blocked, just as if ``__hash__`` had been\n explicitly set to ``None``.\n\nobject.__bool__(self)\n\n Called to implement truth value testing and the built-in operation\n ``bool()``; should return ``False`` or ``True``. When this method\n is not defined, ``__len__()`` is called, if it is defined, and the\n object is considered true if its result is nonzero. If a class\n defines neither ``__len__()`` nor ``__bool__()``, all its instances\n are considered true.\n\n\nCustomizing attribute access\n============================\n\nThe following methods can be defined to customize the meaning of\nattribute access (use of, assignment to, or deletion of ``x.name``)\nfor class instances.\n\nobject.__getattr__(self, name)\n\n Called when an attribute lookup has not found the attribute in the\n usual places (i.e. it is not an instance attribute nor is it found\n in the class tree for ``self``). ``name`` is the attribute name.\n This method should return the (computed) attribute value or raise\n an ``AttributeError`` exception.\n\n Note that if the attribute is found through the normal mechanism,\n ``__getattr__()`` is not called. (This is an intentional asymmetry\n between ``__getattr__()`` and ``__setattr__()``.) This is done both\n for efficiency reasons and because otherwise ``__getattr__()``\n would have no way to access other attributes of the instance. Note\n that at least for instance variables, you can fake total control by\n not inserting any values in the instance attribute dictionary (but\n instead inserting them in another object). See the\n ``__getattribute__()`` method below for a way to actually get total\n control over attribute access.\n\nobject.__getattribute__(self, name)\n\n Called unconditionally to implement attribute accesses for\n instances of the class. If the class also defines\n ``__getattr__()``, the latter will not be called unless\n ``__getattribute__()`` either calls it explicitly or raises an\n ``AttributeError``. This method should return the (computed)\n attribute value or raise an ``AttributeError`` exception. In order\n to avoid infinite recursion in this method, its implementation\n should always call the base class method with the same name to\n access any attributes it needs, for example,\n ``object.__getattribute__(self, name)``.\n\n Note: This method may still be bypassed when looking up special methods\n as the result of implicit invocation via language syntax or\n built-in functions. See *Special method lookup*.\n\nobject.__setattr__(self, name, value)\n\n Called when an attribute assignment is attempted. This is called\n instead of the normal mechanism (i.e. store the value in the\n instance dictionary). *name* is the attribute name, *value* is the\n value to be assigned to it.\n\n If ``__setattr__()`` wants to assign to an instance attribute, it\n should call the base class method with the same name, for example,\n ``object.__setattr__(self, name, value)``.\n\nobject.__delattr__(self, name)\n\n Like ``__setattr__()`` but for attribute deletion instead of\n assignment. This should only be implemented if ``del obj.name`` is\n meaningful for the object.\n\nobject.__dir__(self)\n\n Called when ``dir()`` is called on the object. A list must be\n returned.\n\n\nImplementing Descriptors\n------------------------\n\nThe following methods only apply when an instance of the class\ncontaining the method (a so-called *descriptor* class) appears in the\nclass dictionary of another class, known as the *owner* class. In the\nexamples below, "the attribute" refers to the attribute whose name is\nthe key of the property in the owner class\' ``__dict__``.\n\nobject.__get__(self, instance, owner)\n\n Called to get the attribute of the owner class (class attribute\n access) or of an instance of that class (instance attribute\n access). *owner* is always the owner class, while *instance* is the\n instance that the attribute was accessed through, or ``None`` when\n the attribute is accessed through the *owner*. This method should\n return the (computed) attribute value or raise an\n ``AttributeError`` exception.\n\nobject.__set__(self, instance, value)\n\n Called to set the attribute on an instance *instance* of the owner\n class to a new value, *value*.\n\nobject.__delete__(self, instance)\n\n Called to delete the attribute on an instance *instance* of the\n owner class.\n\n\nInvoking Descriptors\n--------------------\n\nIn general, a descriptor is an object attribute with "binding\nbehavior", one whose attribute access has been overridden by methods\nin the descriptor protocol: ``__get__()``, ``__set__()``, and\n``__delete__()``. If any of those methods are defined for an object,\nit is said to be a descriptor.\n\nThe default behavior for attribute access is to get, set, or delete\nthe attribute from an object\'s dictionary. For instance, ``a.x`` has a\nlookup chain starting with ``a.__dict__[\'x\']``, then\n``type(a).__dict__[\'x\']``, and continuing through the base classes of\n``type(a)`` excluding metaclasses.\n\nHowever, if the looked-up value is an object defining one of the\ndescriptor methods, then Python may override the default behavior and\ninvoke the descriptor method instead. Where this occurs in the\nprecedence chain depends on which descriptor methods were defined and\nhow they were called.\n\nThe starting point for descriptor invocation is a binding, ``a.x``.\nHow the arguments are assembled depends on ``a``:\n\nDirect Call\n The simplest and least common call is when user code directly\n invokes a descriptor method: ``x.__get__(a)``.\n\nInstance Binding\n If binding to an object instance, ``a.x`` is transformed into the\n call: ``type(a).__dict__[\'x\'].__get__(a, type(a))``.\n\nClass Binding\n If binding to a class, ``A.x`` is transformed into the call:\n ``A.__dict__[\'x\'].__get__(None, A)``.\n\nSuper Binding\n If ``a`` is an instance of ``super``, then the binding ``super(B,\n obj).m()`` searches ``obj.__class__.__mro__`` for the base class\n ``A`` immediately preceding ``B`` and then invokes the descriptor\n with the call: ``A.__dict__[\'m\'].__get__(obj, A)``.\n\nFor instance bindings, the precedence of descriptor invocation depends\non the which descriptor methods are defined. A descriptor can define\nany combination of ``__get__()``, ``__set__()`` and ``__delete__()``.\nIf it does not define ``__get__()``, then accessing the attribute will\nreturn the descriptor object itself unless there is a value in the\nobject\'s instance dictionary. If the descriptor defines ``__set__()``\nand/or ``__delete__()``, it is a data descriptor; if it defines\nneither, it is a non-data descriptor. Normally, data descriptors\ndefine both ``__get__()`` and ``__set__()``, while non-data\ndescriptors have just the ``__get__()`` method. Data descriptors with\n``__set__()`` and ``__get__()`` defined always override a redefinition\nin an instance dictionary. In contrast, non-data descriptors can be\noverridden by instances.\n\nPython methods (including ``staticmethod()`` and ``classmethod()``)\nare implemented as non-data descriptors. Accordingly, instances can\nredefine and override methods. This allows individual instances to\nacquire behaviors that differ from other instances of the same class.\n\nThe ``property()`` function is implemented as a data descriptor.\nAccordingly, instances cannot override the behavior of a property.\n\n\n__slots__\n---------\n\nBy default, instances of classes have a dictionary for attribute\nstorage. This wastes space for objects having very few instance\nvariables. The space consumption can become acute when creating large\nnumbers of instances.\n\nThe default can be overridden by defining *__slots__* in a class\ndefinition. The *__slots__* declaration takes a sequence of instance\nvariables and reserves just enough space in each instance to hold a\nvalue for each variable. Space is saved because *__dict__* is not\ncreated for each instance.\n\nobject.__slots__\n\n This class variable can be assigned a string, iterable, or sequence\n of strings with variable names used by instances. If defined in a\n class, *__slots__* reserves space for the declared variables and\n prevents the automatic creation of *__dict__* and *__weakref__* for\n each instance.\n\n\nNotes on using *__slots__*\n~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n* When inheriting from a class without *__slots__*, the *__dict__*\n attribute of that class will always be accessible, so a *__slots__*\n definition in the subclass is meaningless.\n\n* Without a *__dict__* variable, instances cannot be assigned new\n variables not listed in the *__slots__* definition. Attempts to\n assign to an unlisted variable name raises ``AttributeError``. If\n dynamic assignment of new variables is desired, then add\n ``\'__dict__\'`` to the sequence of strings in the *__slots__*\n declaration.\n\n* Without a *__weakref__* variable for each instance, classes defining\n *__slots__* do not support weak references to its instances. If weak\n reference support is needed, then add ``\'__weakref__\'`` to the\n sequence of strings in the *__slots__* declaration.\n\n* *__slots__* are implemented at the class level by creating\n descriptors (*Implementing Descriptors*) for each variable name. As\n a result, class attributes cannot be used to set default values for\n instance variables defined by *__slots__*; otherwise, the class\n attribute would overwrite the descriptor assignment.\n\n* The action of a *__slots__* declaration is limited to the class\n where it is defined. As a result, subclasses will have a *__dict__*\n unless they also define *__slots__* (which must only contain names\n of any *additional* slots).\n\n* If a class defines a slot also defined in a base class, the instance\n variable defined by the base class slot is inaccessible (except by\n retrieving its descriptor directly from the base class). This\n renders the meaning of the program undefined. In the future, a\n check may be added to prevent this.\n\n* Nonempty *__slots__* does not work for classes derived from\n "variable-length" built-in types such as ``int``, ``str`` and\n ``tuple``.\n\n* Any non-string iterable may be assigned to *__slots__*. Mappings may\n also be used; however, in the future, special meaning may be\n assigned to the values corresponding to each key.\n\n* *__class__* assignment works only if both classes have the same\n *__slots__*.\n\n\nCustomizing class creation\n==========================\n\nBy default, classes are constructed using ``type()``. A class\ndefinition is read into a separate namespace and the value of class\nname is bound to the result of ``type(name, bases, dict)``.\n\nWhen the class definition is read, if a callable ``metaclass`` keyword\nargument is passed after the bases in the class definition, the\ncallable given will be called instead of ``type()``. If other keyword\narguments are passed, they will also be passed to the metaclass. This\nallows classes or functions to be written which monitor or alter the\nclass creation process:\n\n* Modifying the class dictionary prior to the class being created.\n\n* Returning an instance of another class -- essentially performing the\n role of a factory function.\n\nThese steps will have to be performed in the metaclass\'s ``__new__()``\nmethod -- ``type.__new__()`` can then be called from this method to\ncreate a class with different properties. This example adds a new\nelement to the class dictionary before creating the class:\n\n class metacls(type):\n def __new__(mcs, name, bases, dict):\n dict[\'foo\'] = \'metacls was here\'\n return type.__new__(mcs, name, bases, dict)\n\nYou can of course also override other class methods (or add new\nmethods); for example defining a custom ``__call__()`` method in the\nmetaclass allows custom behavior when the class is called, e.g. not\nalways creating a new instance.\n\nIf the metaclass has a ``__prepare__()`` attribute (usually\nimplemented as a class or static method), it is called before the\nclass body is evaluated with the name of the class and a tuple of its\nbases for arguments. It should return an object that supports the\nmapping interface that will be used to store the namespace of the\nclass. The default is a plain dictionary. This could be used, for\nexample, to keep track of the order that class attributes are declared\nin by returning an ordered dictionary.\n\nThe appropriate metaclass is determined by the following precedence\nrules:\n\n* If the ``metaclass`` keyword argument is passed with the bases, it\n is used.\n\n* Otherwise, if there is at least one base class, its metaclass is\n used.\n\n* Otherwise, the default metaclass (``type``) is used.\n\nThe potential uses for metaclasses are boundless. Some ideas that have\nbeen explored including logging, interface checking, automatic\ndelegation, automatic property creation, proxies, frameworks, and\nautomatic resource locking/synchronization.\n\nHere is an example of a metaclass that uses an\n``collections.OrderedDict`` to remember the order that class members\nwere defined:\n\n class OrderedClass(type):\n\n @classmethod\n def __prepare__(metacls, name, bases, **kwds):\n return collections.OrderedDict()\n\n def __new__(cls, name, bases, classdict):\n result = type.__new__(cls, name, bases, dict(classdict))\n result.members = tuple(classdict)\n return result\n\n class A(metaclass=OrderedClass):\n def one(self): pass\n def two(self): pass\n def three(self): pass\n def four(self): pass\n\n >>> A.members\n (\'__module__\', \'one\', \'two\', \'three\', \'four\')\n\nWhen the class definition for *A* gets executed, the process begins\nwith calling the metaclass\'s ``__prepare__()`` method which returns an\nempty ``collections.OrderedDict``. That mapping records the methods\nand attributes of *A* as they are defined within the body of the class\nstatement. Once those definitions are executed, the ordered dictionary\nis fully populated and the metaclass\'s ``__new__()`` method gets\ninvoked. That method builds the new type and it saves the ordered\ndictionary keys in an attribute called ``members``.\n\n\nCustomizing instance and subclass checks\n========================================\n\nThe following methods are used to override the default behavior of the\n``isinstance()`` and ``issubclass()`` built-in functions.\n\nIn particular, the metaclass ``abc.ABCMeta`` implements these methods\nin order to allow the addition of Abstract Base Classes (ABCs) as\n"virtual base classes" to any class or type (including built-in\ntypes), including other ABCs.\n\nclass.__instancecheck__(self, instance)\n\n Return true if *instance* should be considered a (direct or\n indirect) instance of *class*. If defined, called to implement\n ``isinstance(instance, class)``.\n\nclass.__subclasscheck__(self, subclass)\n\n Return true if *subclass* should be considered a (direct or\n indirect) subclass of *class*. If defined, called to implement\n ``issubclass(subclass, class)``.\n\nNote that these methods are looked up on the type (metaclass) of a\nclass. They cannot be defined as class methods in the actual class.\nThis is consistent with the lookup of special methods that are called\non instances, only in this case the instance is itself a class.\n\nSee also:\n\n **PEP 3119** - Introducing Abstract Base Classes\n Includes the specification for customizing ``isinstance()`` and\n ``issubclass()`` behavior through ``__instancecheck__()`` and\n ``__subclasscheck__()``, with motivation for this functionality\n in the context of adding Abstract Base Classes (see the ``abc``\n module) to the language.\n\n\nEmulating callable objects\n==========================\n\nobject.__call__(self[, args...])\n\n Called when the instance is "called" as a function; if this method\n is defined, ``x(arg1, arg2, ...)`` is a shorthand for\n ``x.__call__(arg1, arg2, ...)``.\n\n\nEmulating container types\n=========================\n\nThe following methods can be defined to implement container objects.\nContainers usually are sequences (such as lists or tuples) or mappings\n(like dictionaries), but can represent other containers as well. The\nfirst set of methods is used either to emulate a sequence or to\nemulate a mapping; the difference is that for a sequence, the\nallowable keys should be the integers *k* for which ``0 <= k < N``\nwhere *N* is the length of the sequence, or slice objects, which\ndefine a range of items. It is also recommended that mappings provide\nthe methods ``keys()``, ``values()``, ``items()``, ``get()``,\n``clear()``, ``setdefault()``, ``pop()``, ``popitem()``, ``copy()``,\nand ``update()`` behaving similar to those for Python\'s standard\ndictionary objects. The ``collections`` module provides a\n``MutableMapping`` abstract base class to help create those methods\nfrom a base set of ``__getitem__()``, ``__setitem__()``,\n``__delitem__()``, and ``keys()``. Mutable sequences should provide\nmethods ``append()``, ``count()``, ``index()``, ``extend()``,\n``insert()``, ``pop()``, ``remove()``, ``reverse()`` and ``sort()``,\nlike Python standard list objects. Finally, sequence types should\nimplement addition (meaning concatenation) and multiplication (meaning\nrepetition) by defining the methods ``__add__()``, ``__radd__()``,\n``__iadd__()``, ``__mul__()``, ``__rmul__()`` and ``__imul__()``\ndescribed below; they should not define other numerical operators. It\nis recommended that both mappings and sequences implement the\n``__contains__()`` method to allow efficient use of the ``in``\noperator; for mappings, ``in`` should search the mapping\'s keys; for\nsequences, it should search through the values. It is further\nrecommended that both mappings and sequences implement the\n``__iter__()`` method to allow efficient iteration through the\ncontainer; for mappings, ``__iter__()`` should be the same as\n``keys()``; for sequences, it should iterate through the values.\n\nobject.__len__(self)\n\n Called to implement the built-in function ``len()``. Should return\n the length of the object, an integer ``>=`` 0. Also, an object\n that doesn\'t define a ``__bool__()`` method and whose ``__len__()``\n method returns zero is considered to be false in a Boolean context.\n\nNote: Slicing is done exclusively with the following three methods. A\n call like\n\n a[1:2] = b\n\n is translated to\n\n a[slice(1, 2, None)] = b\n\n and so forth. Missing slice items are always filled in with\n ``None``.\n\nobject.__getitem__(self, key)\n\n Called to implement evaluation of ``self[key]``. For sequence\n types, the accepted keys should be integers and slice objects.\n Note that the special interpretation of negative indexes (if the\n class wishes to emulate a sequence type) is up to the\n ``__getitem__()`` method. If *key* is of an inappropriate type,\n ``TypeError`` may be raised; if of a value outside the set of\n indexes for the sequence (after any special interpretation of\n negative values), ``IndexError`` should be raised. For mapping\n types, if *key* is missing (not in the container), ``KeyError``\n should be raised.\n\n Note: ``for`` loops expect that an ``IndexError`` will be raised for\n illegal indexes to allow proper detection of the end of the\n sequence.\n\nobject.__setitem__(self, key, value)\n\n Called to implement assignment to ``self[key]``. Same note as for\n ``__getitem__()``. This should only be implemented for mappings if\n the objects support changes to the values for keys, or if new keys\n can be added, or for sequences if elements can be replaced. The\n same exceptions should be raised for improper *key* values as for\n the ``__getitem__()`` method.\n\nobject.__delitem__(self, key)\n\n Called to implement deletion of ``self[key]``. Same note as for\n ``__getitem__()``. This should only be implemented for mappings if\n the objects support removal of keys, or for sequences if elements\n can be removed from the sequence. The same exceptions should be\n raised for improper *key* values as for the ``__getitem__()``\n method.\n\nobject.__iter__(self)\n\n This method is called when an iterator is required for a container.\n This method should return a new iterator object that can iterate\n over all the objects in the container. For mappings, it should\n iterate over the keys of the container, and should also be made\n available as the method ``keys()``.\n\n Iterator objects also need to implement this method; they are\n required to return themselves. For more information on iterator\n objects, see *Iterator Types*.\n\nobject.__reversed__(self)\n\n Called (if present) by the ``reversed()`` built-in to implement\n reverse iteration. It should return a new iterator object that\n iterates over all the objects in the container in reverse order.\n\n If the ``__reversed__()`` method is not provided, the\n ``reversed()`` built-in will fall back to using the sequence\n protocol (``__len__()`` and ``__getitem__()``). Objects that\n support the sequence protocol should only provide\n ``__reversed__()`` if they can provide an implementation that is\n more efficient than the one provided by ``reversed()``.\n\nThe membership test operators (``in`` and ``not in``) are normally\nimplemented as an iteration through a sequence. However, container\nobjects can supply the following special method with a more efficient\nimplementation, which also does not require the object be a sequence.\n\nobject.__contains__(self, item)\n\n Called to implement membership test operators. Should return true\n if *item* is in *self*, false otherwise. For mapping objects, this\n should consider the keys of the mapping rather than the values or\n the key-item pairs.\n\n For objects that don\'t define ``__contains__()``, the membership\n test first tries iteration via ``__iter__()``, then the old\n sequence iteration protocol via ``__getitem__()``, see *this\n section in the language reference*.\n\n\nEmulating numeric types\n=======================\n\nThe following methods can be defined to emulate numeric objects.\nMethods corresponding to operations that are not supported by the\nparticular kind of number implemented (e.g., bitwise operations for\nnon-integral numbers) should be left undefined.\n\nobject.__add__(self, other)\nobject.__sub__(self, other)\nobject.__mul__(self, other)\nobject.__truediv__(self, other)\nobject.__floordiv__(self, other)\nobject.__mod__(self, other)\nobject.__divmod__(self, other)\nobject.__pow__(self, other[, modulo])\nobject.__lshift__(self, other)\nobject.__rshift__(self, other)\nobject.__and__(self, other)\nobject.__xor__(self, other)\nobject.__or__(self, other)\n\n These methods are called to implement the binary arithmetic\n operations (``+``, ``-``, ``*``, ``/``, ``//``, ``%``,\n ``divmod()``, ``pow()``, ``**``, ``<<``, ``>>``, ``&``, ``^``,\n ``|``). For instance, to evaluate the expression ``x + y``, where\n *x* is an instance of a class that has an ``__add__()`` method,\n ``x.__add__(y)`` is called. The ``__divmod__()`` method should be\n the equivalent to using ``__floordiv__()`` and ``__mod__()``; it\n should not be related to ``__truediv__()``. Note that\n ``__pow__()`` should be defined to accept an optional third\n argument if the ternary version of the built-in ``pow()`` function\n is to be supported.\n\n If one of those methods does not support the operation with the\n supplied arguments, it should return ``NotImplemented``.\n\nobject.__radd__(self, other)\nobject.__rsub__(self, other)\nobject.__rmul__(self, other)\nobject.__rtruediv__(self, other)\nobject.__rfloordiv__(self, other)\nobject.__rmod__(self, other)\nobject.__rdivmod__(self, other)\nobject.__rpow__(self, other)\nobject.__rlshift__(self, other)\nobject.__rrshift__(self, other)\nobject.__rand__(self, other)\nobject.__rxor__(self, other)\nobject.__ror__(self, other)\n\n These methods are called to implement the binary arithmetic\n operations (``+``, ``-``, ``*``, ``/``, ``//``, ``%``,\n ``divmod()``, ``pow()``, ``**``, ``<<``, ``>>``, ``&``, ``^``,\n ``|``) with reflected (swapped) operands. These functions are only\n called if the left operand does not support the corresponding\n operation and the operands are of different types. [2] For\n instance, to evaluate the expression ``x - y``, where *y* is an\n instance of a class that has an ``__rsub__()`` method,\n ``y.__rsub__(x)`` is called if ``x.__sub__(y)`` returns\n *NotImplemented*.\n\n Note that ternary ``pow()`` will not try calling ``__rpow__()``\n (the coercion rules would become too complicated).\n\n Note: If the right operand\'s type is a subclass of the left operand\'s\n type and that subclass provides the reflected method for the\n operation, this method will be called before the left operand\'s\n non-reflected method. This behavior allows subclasses to\n override their ancestors\' operations.\n\nobject.__iadd__(self, other)\nobject.__isub__(self, other)\nobject.__imul__(self, other)\nobject.__itruediv__(self, other)\nobject.__ifloordiv__(self, other)\nobject.__imod__(self, other)\nobject.__ipow__(self, other[, modulo])\nobject.__ilshift__(self, other)\nobject.__irshift__(self, other)\nobject.__iand__(self, other)\nobject.__ixor__(self, other)\nobject.__ior__(self, other)\n\n These methods are called to implement the augmented arithmetic\n assignments (``+=``, ``-=``, ``*=``, ``/=``, ``//=``, ``%=``,\n ``**=``, ``<<=``, ``>>=``, ``&=``, ``^=``, ``|=``). These methods\n should attempt to do the operation in-place (modifying *self*) and\n return the result (which could be, but does not have to be,\n *self*). If a specific method is not defined, the augmented\n assignment falls back to the normal methods. For instance, to\n execute the statement ``x += y``, where *x* is an instance of a\n class that has an ``__iadd__()`` method, ``x.__iadd__(y)`` is\n called. If *x* is an instance of a class that does not define a\n ``__iadd__()`` method, ``x.__add__(y)`` and ``y.__radd__(x)`` are\n considered, as with the evaluation of ``x + y``.\n\nobject.__neg__(self)\nobject.__pos__(self)\nobject.__abs__(self)\nobject.__invert__(self)\n\n Called to implement the unary arithmetic operations (``-``, ``+``,\n ``abs()`` and ``~``).\n\nobject.__complex__(self)\nobject.__int__(self)\nobject.__float__(self)\nobject.__round__(self[, n])\n\n Called to implement the built-in functions ``complex()``,\n ``int()``, ``float()`` and ``round()``. Should return a value of\n the appropriate type.\n\nobject.__index__(self)\n\n Called to implement ``operator.index()``. Also called whenever\n Python needs an integer object (such as in slicing, or in the\n built-in ``bin()``, ``hex()`` and ``oct()`` functions). Must return\n an integer.\n\n\nWith Statement Context Managers\n===============================\n\nA *context manager* is an object that defines the runtime context to\nbe established when executing a ``with`` statement. The context\nmanager handles the entry into, and the exit from, the desired runtime\ncontext for the execution of the block of code. Context managers are\nnormally invoked using the ``with`` statement (described in section\n*The with statement*), but can also be used by directly invoking their\nmethods.\n\nTypical uses of context managers include saving and restoring various\nkinds of global state, locking and unlocking resources, closing opened\nfiles, etc.\n\nFor more information on context managers, see *Context Manager Types*.\n\nobject.__enter__(self)\n\n Enter the runtime context related to this object. The ``with``\n statement will bind this method\'s return value to the target(s)\n specified in the ``as`` clause of the statement, if any.\n\nobject.__exit__(self, exc_type, exc_value, traceback)\n\n Exit the runtime context related to this object. The parameters\n describe the exception that caused the context to be exited. If the\n context was exited without an exception, all three arguments will\n be ``None``.\n\n If an exception is supplied, and the method wishes to suppress the\n exception (i.e., prevent it from being propagated), it should\n return a true value. Otherwise, the exception will be processed\n normally upon exit from this method.\n\n Note that ``__exit__()`` methods should not reraise the passed-in\n exception; this is the caller\'s responsibility.\n\nSee also:\n\n **PEP 0343** - The "with" statement\n The specification, background, and examples for the Python\n ``with`` statement.\n\n\nSpecial method lookup\n=====================\n\nFor custom classes, implicit invocations of special methods are only\nguaranteed to work correctly if defined on an object\'s type, not in\nthe object\'s instance dictionary. That behaviour is the reason why\nthe following code raises an exception:\n\n >>> class C:\n ... pass\n ...\n >>> c = C()\n >>> c.__len__ = lambda: 5\n >>> len(c)\n Traceback (most recent call last):\n File "", line 1, in \n TypeError: object of type \'C\' has no len()\n\nThe rationale behind this behaviour lies with a number of special\nmethods such as ``__hash__()`` and ``__repr__()`` that are implemented\nby all objects, including type objects. If the implicit lookup of\nthese methods used the conventional lookup process, they would fail\nwhen invoked on the type object itself:\n\n >>> 1 .__hash__() == hash(1)\n True\n >>> int.__hash__() == hash(int)\n Traceback (most recent call last):\n File "", line 1, in \n TypeError: descriptor \'__hash__\' of \'int\' object needs an argument\n\nIncorrectly attempting to invoke an unbound method of a class in this\nway is sometimes referred to as \'metaclass confusion\', and is avoided\nby bypassing the instance when looking up special methods:\n\n >>> type(1).__hash__(1) == hash(1)\n True\n >>> type(int).__hash__(int) == hash(int)\n True\n\nIn addition to bypassing any instance attributes in the interest of\ncorrectness, implicit special method lookup generally also bypasses\nthe ``__getattribute__()`` method even of the object\'s metaclass:\n\n >>> class Meta(type):\n ... def __getattribute__(*args):\n ... print("Metaclass getattribute invoked")\n ... return type.__getattribute__(*args)\n ...\n >>> class C(object, metaclass=Meta):\n ... def __len__(self):\n ... return 10\n ... def __getattribute__(*args):\n ... print("Class getattribute invoked")\n ... return object.__getattribute__(*args)\n ...\n >>> c = C()\n >>> c.__len__() # Explicit lookup via instance\n Class getattribute invoked\n 10\n >>> type(c).__len__(c) # Explicit lookup via type\n Metaclass getattribute invoked\n 10\n >>> len(c) # Implicit lookup\n 10\n\nBypassing the ``__getattribute__()`` machinery in this fashion\nprovides significant scope for speed optimisations within the\ninterpreter, at the cost of some flexibility in the handling of\nspecial methods (the special method *must* be set on the class object\nitself in order to be consistently invoked by the interpreter).\n\n-[ Footnotes ]-\n\n[1] It *is* possible in some cases to change an object\'s type, under\n certain controlled conditions. It generally isn\'t a good idea\n though, since it can lead to some very strange behaviour if it is\n handled incorrectly.\n\n[2] For operands of the same type, it is assumed that if the non-\n reflected method (such as ``__add__()``) fails the operation is\n not supported, which is why the reflected method is not called.\n', + 'specialnames': '\nSpecial method names\n********************\n\nA class can implement certain operations that are invoked by special\nsyntax (such as arithmetic operations or subscripting and slicing) by\ndefining methods with special names. This is Python\'s approach to\n*operator overloading*, allowing classes to define their own behavior\nwith respect to language operators. For instance, if a class defines\na method named ``__getitem__()``, and ``x`` is an instance of this\nclass, then ``x[i]`` is roughly equivalent to ``type(x).__getitem__(x,\ni)``. Except where mentioned, attempts to execute an operation raise\nan exception when no appropriate method is defined (typically\n``AttributeError`` or ``TypeError``).\n\nWhen implementing a class that emulates any built-in type, it is\nimportant that the emulation only be implemented to the degree that it\nmakes sense for the object being modelled. For example, some\nsequences may work well with retrieval of individual elements, but\nextracting a slice may not make sense. (One example of this is the\n``NodeList`` interface in the W3C\'s Document Object Model.)\n\n\nBasic customization\n===================\n\nobject.__new__(cls[, ...])\n\n Called to create a new instance of class *cls*. ``__new__()`` is a\n static method (special-cased so you need not declare it as such)\n that takes the class of which an instance was requested as its\n first argument. The remaining arguments are those passed to the\n object constructor expression (the call to the class). The return\n value of ``__new__()`` should be the new object instance (usually\n an instance of *cls*).\n\n Typical implementations create a new instance of the class by\n invoking the superclass\'s ``__new__()`` method using\n ``super(currentclass, cls).__new__(cls[, ...])`` with appropriate\n arguments and then modifying the newly-created instance as\n necessary before returning it.\n\n If ``__new__()`` returns an instance of *cls*, then the new\n instance\'s ``__init__()`` method will be invoked like\n ``__init__(self[, ...])``, where *self* is the new instance and the\n remaining arguments are the same as were passed to ``__new__()``.\n\n If ``__new__()`` does not return an instance of *cls*, then the new\n instance\'s ``__init__()`` method will not be invoked.\n\n ``__new__()`` is intended mainly to allow subclasses of immutable\n types (like int, str, or tuple) to customize instance creation. It\n is also commonly overridden in custom metaclasses in order to\n customize class creation.\n\nobject.__init__(self[, ...])\n\n Called when the instance is created. The arguments are those\n passed to the class constructor expression. If a base class has an\n ``__init__()`` method, the derived class\'s ``__init__()`` method,\n if any, must explicitly call it to ensure proper initialization of\n the base class part of the instance; for example:\n ``BaseClass.__init__(self, [args...])``. As a special constraint\n on constructors, no value may be returned; doing so will cause a\n ``TypeError`` to be raised at runtime.\n\nobject.__del__(self)\n\n Called when the instance is about to be destroyed. This is also\n called a destructor. If a base class has a ``__del__()`` method,\n the derived class\'s ``__del__()`` method, if any, must explicitly\n call it to ensure proper deletion of the base class part of the\n instance. Note that it is possible (though not recommended!) for\n the ``__del__()`` method to postpone destruction of the instance by\n creating a new reference to it. It may then be called at a later\n time when this new reference is deleted. It is not guaranteed that\n ``__del__()`` methods are called for objects that still exist when\n the interpreter exits.\n\n Note: ``del x`` doesn\'t directly call ``x.__del__()`` --- the former\n decrements the reference count for ``x`` by one, and the latter\n is only called when ``x``\'s reference count reaches zero. Some\n common situations that may prevent the reference count of an\n object from going to zero include: circular references between\n objects (e.g., a doubly-linked list or a tree data structure with\n parent and child pointers); a reference to the object on the\n stack frame of a function that caught an exception (the traceback\n stored in ``sys.exc_info()[2]`` keeps the stack frame alive); or\n a reference to the object on the stack frame that raised an\n unhandled exception in interactive mode (the traceback stored in\n ``sys.last_traceback`` keeps the stack frame alive). The first\n situation can only be remedied by explicitly breaking the cycles;\n the latter two situations can be resolved by storing ``None`` in\n ``sys.last_traceback``. Circular references which are garbage are\n detected when the option cycle detector is enabled (it\'s on by\n default), but can only be cleaned up if there are no Python-\n level ``__del__()`` methods involved. Refer to the documentation\n for the ``gc`` module for more information about how\n ``__del__()`` methods are handled by the cycle detector,\n particularly the description of the ``garbage`` value.\n\n Warning: Due to the precarious circumstances under which ``__del__()``\n methods are invoked, exceptions that occur during their execution\n are ignored, and a warning is printed to ``sys.stderr`` instead.\n Also, when ``__del__()`` is invoked in response to a module being\n deleted (e.g., when execution of the program is done), other\n globals referenced by the ``__del__()`` method may already have\n been deleted or in the process of being torn down (e.g. the\n import machinery shutting down). For this reason, ``__del__()``\n methods should do the absolute minimum needed to maintain\n external invariants. Starting with version 1.5, Python\n guarantees that globals whose name begins with a single\n underscore are deleted from their module before other globals are\n deleted; if no other references to such globals exist, this may\n help in assuring that imported modules are still available at the\n time when the ``__del__()`` method is called.\n\nobject.__repr__(self)\n\n Called by the ``repr()`` built-in function to compute the\n "official" string representation of an object. If at all possible,\n this should look like a valid Python expression that could be used\n to recreate an object with the same value (given an appropriate\n environment). If this is not possible, a string of the form\n ``<...some useful description...>`` should be returned. The return\n value must be a string object. If a class defines ``__repr__()``\n but not ``__str__()``, then ``__repr__()`` is also used when an\n "informal" string representation of instances of that class is\n required.\n\n This is typically used for debugging, so it is important that the\n representation is information-rich and unambiguous.\n\nobject.__str__(self)\n\n Called by the ``str()`` built-in function and by the ``print()``\n function to compute the "informal" string representation of an\n object. This differs from ``__repr__()`` in that it does not have\n to be a valid Python expression: a more convenient or concise\n representation may be used instead. The return value must be a\n string object.\n\nobject.__format__(self, format_spec)\n\n Called by the ``format()`` built-in function (and by extension, the\n ``format()`` method of class ``str``) to produce a "formatted"\n string representation of an object. The ``format_spec`` argument is\n a string that contains a description of the formatting options\n desired. The interpretation of the ``format_spec`` argument is up\n to the type implementing ``__format__()``, however most classes\n will either delegate formatting to one of the built-in types, or\n use a similar formatting option syntax.\n\n See *Format Specification Mini-Language* for a description of the\n standard formatting syntax.\n\n The return value must be a string object.\n\nobject.__lt__(self, other)\nobject.__le__(self, other)\nobject.__eq__(self, other)\nobject.__ne__(self, other)\nobject.__gt__(self, other)\nobject.__ge__(self, other)\n\n These are the so-called "rich comparison" methods. The\n correspondence between operator symbols and method names is as\n follows: ``xy`` calls ``x.__gt__(y)``, and ``x>=y`` calls\n ``x.__ge__(y)``.\n\n A rich comparison method may return the singleton\n ``NotImplemented`` if it does not implement the operation for a\n given pair of arguments. By convention, ``False`` and ``True`` are\n returned for a successful comparison. However, these methods can\n return any value, so if the comparison operator is used in a\n Boolean context (e.g., in the condition of an ``if`` statement),\n Python will call ``bool()`` on the value to determine if the result\n is true or false.\n\n There are no implied relationships among the comparison operators.\n The truth of ``x==y`` does not imply that ``x!=y`` is false.\n Accordingly, when defining ``__eq__()``, one should also define\n ``__ne__()`` so that the operators will behave as expected. See\n the paragraph on ``__hash__()`` for some important notes on\n creating *hashable* objects which support custom comparison\n operations and are usable as dictionary keys.\n\n There are no swapped-argument versions of these methods (to be used\n when the left argument does not support the operation but the right\n argument does); rather, ``__lt__()`` and ``__gt__()`` are each\n other\'s reflection, ``__le__()`` and ``__ge__()`` are each other\'s\n reflection, and ``__eq__()`` and ``__ne__()`` are their own\n reflection.\n\n Arguments to rich comparison methods are never coerced.\n\n To automatically generate ordering operations from a single root\n operation, see ``functools.total_ordering()``.\n\nobject.__hash__(self)\n\n Called by built-in function ``hash()`` and for operations on\n members of hashed collections including ``set``, ``frozenset``, and\n ``dict``. ``__hash__()`` should return an integer. The only\n required property is that objects which compare equal have the same\n hash value; it is advised to somehow mix together (e.g. using\n exclusive or) the hash values for the components of the object that\n also play a part in comparison of objects.\n\n If a class does not define an ``__eq__()`` method it should not\n define a ``__hash__()`` operation either; if it defines\n ``__eq__()`` but not ``__hash__()``, its instances will not be\n usable as items in hashable collections. If a class defines\n mutable objects and implements an ``__eq__()`` method, it should\n not implement ``__hash__()``, since the implementation of hashable\n collections requires that a key\'s hash value is immutable (if the\n object\'s hash value changes, it will be in the wrong hash bucket).\n\n User-defined classes have ``__eq__()`` and ``__hash__()`` methods\n by default; with them, all objects compare unequal (except with\n themselves) and ``x.__hash__()`` returns ``id(x)``.\n\n Classes which inherit a ``__hash__()`` method from a parent class\n but change the meaning of ``__eq__()`` such that the hash value\n returned is no longer appropriate (e.g. by switching to a value-\n based concept of equality instead of the default identity based\n equality) can explicitly flag themselves as being unhashable by\n setting ``__hash__ = None`` in the class definition. Doing so means\n that not only will instances of the class raise an appropriate\n ``TypeError`` when a program attempts to retrieve their hash value,\n but they will also be correctly identified as unhashable when\n checking ``isinstance(obj, collections.Hashable)`` (unlike classes\n which define their own ``__hash__()`` to explicitly raise\n ``TypeError``).\n\n If a class that overrides ``__eq__()`` needs to retain the\n implementation of ``__hash__()`` from a parent class, the\n interpreter must be told this explicitly by setting ``__hash__ =\n .__hash__``. Otherwise the inheritance of\n ``__hash__()`` will be blocked, just as if ``__hash__`` had been\n explicitly set to ``None``.\n\nobject.__bool__(self)\n\n Called to implement truth value testing and the built-in operation\n ``bool()``; should return ``False`` or ``True``. When this method\n is not defined, ``__len__()`` is called, if it is defined, and the\n object is considered true if its result is nonzero. If a class\n defines neither ``__len__()`` nor ``__bool__()``, all its instances\n are considered true.\n\n\nCustomizing attribute access\n============================\n\nThe following methods can be defined to customize the meaning of\nattribute access (use of, assignment to, or deletion of ``x.name``)\nfor class instances.\n\nobject.__getattr__(self, name)\n\n Called when an attribute lookup has not found the attribute in the\n usual places (i.e. it is not an instance attribute nor is it found\n in the class tree for ``self``). ``name`` is the attribute name.\n This method should return the (computed) attribute value or raise\n an ``AttributeError`` exception.\n\n Note that if the attribute is found through the normal mechanism,\n ``__getattr__()`` is not called. (This is an intentional asymmetry\n between ``__getattr__()`` and ``__setattr__()``.) This is done both\n for efficiency reasons and because otherwise ``__getattr__()``\n would have no way to access other attributes of the instance. Note\n that at least for instance variables, you can fake total control by\n not inserting any values in the instance attribute dictionary (but\n instead inserting them in another object). See the\n ``__getattribute__()`` method below for a way to actually get total\n control over attribute access.\n\nobject.__getattribute__(self, name)\n\n Called unconditionally to implement attribute accesses for\n instances of the class. If the class also defines\n ``__getattr__()``, the latter will not be called unless\n ``__getattribute__()`` either calls it explicitly or raises an\n ``AttributeError``. This method should return the (computed)\n attribute value or raise an ``AttributeError`` exception. In order\n to avoid infinite recursion in this method, its implementation\n should always call the base class method with the same name to\n access any attributes it needs, for example,\n ``object.__getattribute__(self, name)``.\n\n Note: This method may still be bypassed when looking up special methods\n as the result of implicit invocation via language syntax or\n built-in functions. See *Special method lookup*.\n\nobject.__setattr__(self, name, value)\n\n Called when an attribute assignment is attempted. This is called\n instead of the normal mechanism (i.e. store the value in the\n instance dictionary). *name* is the attribute name, *value* is the\n value to be assigned to it.\n\n If ``__setattr__()`` wants to assign to an instance attribute, it\n should call the base class method with the same name, for example,\n ``object.__setattr__(self, name, value)``.\n\nobject.__delattr__(self, name)\n\n Like ``__setattr__()`` but for attribute deletion instead of\n assignment. This should only be implemented if ``del obj.name`` is\n meaningful for the object.\n\nobject.__dir__(self)\n\n Called when ``dir()`` is called on the object. A list must be\n returned.\n\n\nImplementing Descriptors\n------------------------\n\nThe following methods only apply when an instance of the class\ncontaining the method (a so-called *descriptor* class) appears in an\n*owner* class (the descriptor must be in either the owner\'s class\ndictionary or in the class dictionary for one of its parents). In the\nexamples below, "the attribute" refers to the attribute whose name is\nthe key of the property in the owner class\' ``__dict__``.\n\nobject.__get__(self, instance, owner)\n\n Called to get the attribute of the owner class (class attribute\n access) or of an instance of that class (instance attribute\n access). *owner* is always the owner class, while *instance* is the\n instance that the attribute was accessed through, or ``None`` when\n the attribute is accessed through the *owner*. This method should\n return the (computed) attribute value or raise an\n ``AttributeError`` exception.\n\nobject.__set__(self, instance, value)\n\n Called to set the attribute on an instance *instance* of the owner\n class to a new value, *value*.\n\nobject.__delete__(self, instance)\n\n Called to delete the attribute on an instance *instance* of the\n owner class.\n\n\nInvoking Descriptors\n--------------------\n\nIn general, a descriptor is an object attribute with "binding\nbehavior", one whose attribute access has been overridden by methods\nin the descriptor protocol: ``__get__()``, ``__set__()``, and\n``__delete__()``. If any of those methods are defined for an object,\nit is said to be a descriptor.\n\nThe default behavior for attribute access is to get, set, or delete\nthe attribute from an object\'s dictionary. For instance, ``a.x`` has a\nlookup chain starting with ``a.__dict__[\'x\']``, then\n``type(a).__dict__[\'x\']``, and continuing through the base classes of\n``type(a)`` excluding metaclasses.\n\nHowever, if the looked-up value is an object defining one of the\ndescriptor methods, then Python may override the default behavior and\ninvoke the descriptor method instead. Where this occurs in the\nprecedence chain depends on which descriptor methods were defined and\nhow they were called.\n\nThe starting point for descriptor invocation is a binding, ``a.x``.\nHow the arguments are assembled depends on ``a``:\n\nDirect Call\n The simplest and least common call is when user code directly\n invokes a descriptor method: ``x.__get__(a)``.\n\nInstance Binding\n If binding to an object instance, ``a.x`` is transformed into the\n call: ``type(a).__dict__[\'x\'].__get__(a, type(a))``.\n\nClass Binding\n If binding to a class, ``A.x`` is transformed into the call:\n ``A.__dict__[\'x\'].__get__(None, A)``.\n\nSuper Binding\n If ``a`` is an instance of ``super``, then the binding ``super(B,\n obj).m()`` searches ``obj.__class__.__mro__`` for the base class\n ``A`` immediately preceding ``B`` and then invokes the descriptor\n with the call: ``A.__dict__[\'m\'].__get__(obj, obj.__class__)``.\n\nFor instance bindings, the precedence of descriptor invocation depends\non the which descriptor methods are defined. A descriptor can define\nany combination of ``__get__()``, ``__set__()`` and ``__delete__()``.\nIf it does not define ``__get__()``, then accessing the attribute will\nreturn the descriptor object itself unless there is a value in the\nobject\'s instance dictionary. If the descriptor defines ``__set__()``\nand/or ``__delete__()``, it is a data descriptor; if it defines\nneither, it is a non-data descriptor. Normally, data descriptors\ndefine both ``__get__()`` and ``__set__()``, while non-data\ndescriptors have just the ``__get__()`` method. Data descriptors with\n``__set__()`` and ``__get__()`` defined always override a redefinition\nin an instance dictionary. In contrast, non-data descriptors can be\noverridden by instances.\n\nPython methods (including ``staticmethod()`` and ``classmethod()``)\nare implemented as non-data descriptors. Accordingly, instances can\nredefine and override methods. This allows individual instances to\nacquire behaviors that differ from other instances of the same class.\n\nThe ``property()`` function is implemented as a data descriptor.\nAccordingly, instances cannot override the behavior of a property.\n\n\n__slots__\n---------\n\nBy default, instances of classes have a dictionary for attribute\nstorage. This wastes space for objects having very few instance\nvariables. The space consumption can become acute when creating large\nnumbers of instances.\n\nThe default can be overridden by defining *__slots__* in a class\ndefinition. The *__slots__* declaration takes a sequence of instance\nvariables and reserves just enough space in each instance to hold a\nvalue for each variable. Space is saved because *__dict__* is not\ncreated for each instance.\n\nobject.__slots__\n\n This class variable can be assigned a string, iterable, or sequence\n of strings with variable names used by instances. If defined in a\n class, *__slots__* reserves space for the declared variables and\n prevents the automatic creation of *__dict__* and *__weakref__* for\n each instance.\n\n\nNotes on using *__slots__*\n~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n* When inheriting from a class without *__slots__*, the *__dict__*\n attribute of that class will always be accessible, so a *__slots__*\n definition in the subclass is meaningless.\n\n* Without a *__dict__* variable, instances cannot be assigned new\n variables not listed in the *__slots__* definition. Attempts to\n assign to an unlisted variable name raises ``AttributeError``. If\n dynamic assignment of new variables is desired, then add\n ``\'__dict__\'`` to the sequence of strings in the *__slots__*\n declaration.\n\n* Without a *__weakref__* variable for each instance, classes defining\n *__slots__* do not support weak references to its instances. If weak\n reference support is needed, then add ``\'__weakref__\'`` to the\n sequence of strings in the *__slots__* declaration.\n\n* *__slots__* are implemented at the class level by creating\n descriptors (*Implementing Descriptors*) for each variable name. As\n a result, class attributes cannot be used to set default values for\n instance variables defined by *__slots__*; otherwise, the class\n attribute would overwrite the descriptor assignment.\n\n* The action of a *__slots__* declaration is limited to the class\n where it is defined. As a result, subclasses will have a *__dict__*\n unless they also define *__slots__* (which must only contain names\n of any *additional* slots).\n\n* If a class defines a slot also defined in a base class, the instance\n variable defined by the base class slot is inaccessible (except by\n retrieving its descriptor directly from the base class). This\n renders the meaning of the program undefined. In the future, a\n check may be added to prevent this.\n\n* Nonempty *__slots__* does not work for classes derived from\n "variable-length" built-in types such as ``int``, ``str`` and\n ``tuple``.\n\n* Any non-string iterable may be assigned to *__slots__*. Mappings may\n also be used; however, in the future, special meaning may be\n assigned to the values corresponding to each key.\n\n* *__class__* assignment works only if both classes have the same\n *__slots__*.\n\n\nCustomizing class creation\n==========================\n\nBy default, classes are constructed using ``type()``. A class\ndefinition is read into a separate namespace and the value of class\nname is bound to the result of ``type(name, bases, dict)``.\n\nWhen the class definition is read, if a callable ``metaclass`` keyword\nargument is passed after the bases in the class definition, the\ncallable given will be called instead of ``type()``. If other keyword\narguments are passed, they will also be passed to the metaclass. This\nallows classes or functions to be written which monitor or alter the\nclass creation process:\n\n* Modifying the class dictionary prior to the class being created.\n\n* Returning an instance of another class -- essentially performing the\n role of a factory function.\n\nThese steps will have to be performed in the metaclass\'s ``__new__()``\nmethod -- ``type.__new__()`` can then be called from this method to\ncreate a class with different properties. This example adds a new\nelement to the class dictionary before creating the class:\n\n class metacls(type):\n def __new__(mcs, name, bases, dict):\n dict[\'foo\'] = \'metacls was here\'\n return type.__new__(mcs, name, bases, dict)\n\nYou can of course also override other class methods (or add new\nmethods); for example defining a custom ``__call__()`` method in the\nmetaclass allows custom behavior when the class is called, e.g. not\nalways creating a new instance.\n\nIf the metaclass has a ``__prepare__()`` attribute (usually\nimplemented as a class or static method), it is called before the\nclass body is evaluated with the name of the class and a tuple of its\nbases for arguments. It should return an object that supports the\nmapping interface that will be used to store the namespace of the\nclass. The default is a plain dictionary. This could be used, for\nexample, to keep track of the order that class attributes are declared\nin by returning an ordered dictionary.\n\nThe appropriate metaclass is determined by the following precedence\nrules:\n\n* If the ``metaclass`` keyword argument is passed with the bases, it\n is used.\n\n* Otherwise, if there is at least one base class, its metaclass is\n used.\n\n* Otherwise, the default metaclass (``type``) is used.\n\nThe potential uses for metaclasses are boundless. Some ideas that have\nbeen explored including logging, interface checking, automatic\ndelegation, automatic property creation, proxies, frameworks, and\nautomatic resource locking/synchronization.\n\nHere is an example of a metaclass that uses an\n``collections.OrderedDict`` to remember the order that class members\nwere defined:\n\n class OrderedClass(type):\n\n @classmethod\n def __prepare__(metacls, name, bases, **kwds):\n return collections.OrderedDict()\n\n def __new__(cls, name, bases, classdict):\n result = type.__new__(cls, name, bases, dict(classdict))\n result.members = tuple(classdict)\n return result\n\n class A(metaclass=OrderedClass):\n def one(self): pass\n def two(self): pass\n def three(self): pass\n def four(self): pass\n\n >>> A.members\n (\'__module__\', \'one\', \'two\', \'three\', \'four\')\n\nWhen the class definition for *A* gets executed, the process begins\nwith calling the metaclass\'s ``__prepare__()`` method which returns an\nempty ``collections.OrderedDict``. That mapping records the methods\nand attributes of *A* as they are defined within the body of the class\nstatement. Once those definitions are executed, the ordered dictionary\nis fully populated and the metaclass\'s ``__new__()`` method gets\ninvoked. That method builds the new type and it saves the ordered\ndictionary keys in an attribute called ``members``.\n\n\nCustomizing instance and subclass checks\n========================================\n\nThe following methods are used to override the default behavior of the\n``isinstance()`` and ``issubclass()`` built-in functions.\n\nIn particular, the metaclass ``abc.ABCMeta`` implements these methods\nin order to allow the addition of Abstract Base Classes (ABCs) as\n"virtual base classes" to any class or type (including built-in\ntypes), including other ABCs.\n\nclass.__instancecheck__(self, instance)\n\n Return true if *instance* should be considered a (direct or\n indirect) instance of *class*. If defined, called to implement\n ``isinstance(instance, class)``.\n\nclass.__subclasscheck__(self, subclass)\n\n Return true if *subclass* should be considered a (direct or\n indirect) subclass of *class*. If defined, called to implement\n ``issubclass(subclass, class)``.\n\nNote that these methods are looked up on the type (metaclass) of a\nclass. They cannot be defined as class methods in the actual class.\nThis is consistent with the lookup of special methods that are called\non instances, only in this case the instance is itself a class.\n\nSee also:\n\n **PEP 3119** - Introducing Abstract Base Classes\n Includes the specification for customizing ``isinstance()`` and\n ``issubclass()`` behavior through ``__instancecheck__()`` and\n ``__subclasscheck__()``, with motivation for this functionality\n in the context of adding Abstract Base Classes (see the ``abc``\n module) to the language.\n\n\nEmulating callable objects\n==========================\n\nobject.__call__(self[, args...])\n\n Called when the instance is "called" as a function; if this method\n is defined, ``x(arg1, arg2, ...)`` is a shorthand for\n ``x.__call__(arg1, arg2, ...)``.\n\n\nEmulating container types\n=========================\n\nThe following methods can be defined to implement container objects.\nContainers usually are sequences (such as lists or tuples) or mappings\n(like dictionaries), but can represent other containers as well. The\nfirst set of methods is used either to emulate a sequence or to\nemulate a mapping; the difference is that for a sequence, the\nallowable keys should be the integers *k* for which ``0 <= k < N``\nwhere *N* is the length of the sequence, or slice objects, which\ndefine a range of items. It is also recommended that mappings provide\nthe methods ``keys()``, ``values()``, ``items()``, ``get()``,\n``clear()``, ``setdefault()``, ``pop()``, ``popitem()``, ``copy()``,\nand ``update()`` behaving similar to those for Python\'s standard\ndictionary objects. The ``collections`` module provides a\n``MutableMapping`` abstract base class to help create those methods\nfrom a base set of ``__getitem__()``, ``__setitem__()``,\n``__delitem__()``, and ``keys()``. Mutable sequences should provide\nmethods ``append()``, ``count()``, ``index()``, ``extend()``,\n``insert()``, ``pop()``, ``remove()``, ``reverse()`` and ``sort()``,\nlike Python standard list objects. Finally, sequence types should\nimplement addition (meaning concatenation) and multiplication (meaning\nrepetition) by defining the methods ``__add__()``, ``__radd__()``,\n``__iadd__()``, ``__mul__()``, ``__rmul__()`` and ``__imul__()``\ndescribed below; they should not define other numerical operators. It\nis recommended that both mappings and sequences implement the\n``__contains__()`` method to allow efficient use of the ``in``\noperator; for mappings, ``in`` should search the mapping\'s keys; for\nsequences, it should search through the values. It is further\nrecommended that both mappings and sequences implement the\n``__iter__()`` method to allow efficient iteration through the\ncontainer; for mappings, ``__iter__()`` should be the same as\n``keys()``; for sequences, it should iterate through the values.\n\nobject.__len__(self)\n\n Called to implement the built-in function ``len()``. Should return\n the length of the object, an integer ``>=`` 0. Also, an object\n that doesn\'t define a ``__bool__()`` method and whose ``__len__()``\n method returns zero is considered to be false in a Boolean context.\n\nNote: Slicing is done exclusively with the following three methods. A\n call like\n\n a[1:2] = b\n\n is translated to\n\n a[slice(1, 2, None)] = b\n\n and so forth. Missing slice items are always filled in with\n ``None``.\n\nobject.__getitem__(self, key)\n\n Called to implement evaluation of ``self[key]``. For sequence\n types, the accepted keys should be integers and slice objects.\n Note that the special interpretation of negative indexes (if the\n class wishes to emulate a sequence type) is up to the\n ``__getitem__()`` method. If *key* is of an inappropriate type,\n ``TypeError`` may be raised; if of a value outside the set of\n indexes for the sequence (after any special interpretation of\n negative values), ``IndexError`` should be raised. For mapping\n types, if *key* is missing (not in the container), ``KeyError``\n should be raised.\n\n Note: ``for`` loops expect that an ``IndexError`` will be raised for\n illegal indexes to allow proper detection of the end of the\n sequence.\n\nobject.__setitem__(self, key, value)\n\n Called to implement assignment to ``self[key]``. Same note as for\n ``__getitem__()``. This should only be implemented for mappings if\n the objects support changes to the values for keys, or if new keys\n can be added, or for sequences if elements can be replaced. The\n same exceptions should be raised for improper *key* values as for\n the ``__getitem__()`` method.\n\nobject.__delitem__(self, key)\n\n Called to implement deletion of ``self[key]``. Same note as for\n ``__getitem__()``. This should only be implemented for mappings if\n the objects support removal of keys, or for sequences if elements\n can be removed from the sequence. The same exceptions should be\n raised for improper *key* values as for the ``__getitem__()``\n method.\n\nobject.__iter__(self)\n\n This method is called when an iterator is required for a container.\n This method should return a new iterator object that can iterate\n over all the objects in the container. For mappings, it should\n iterate over the keys of the container, and should also be made\n available as the method ``keys()``.\n\n Iterator objects also need to implement this method; they are\n required to return themselves. For more information on iterator\n objects, see *Iterator Types*.\n\nobject.__reversed__(self)\n\n Called (if present) by the ``reversed()`` built-in to implement\n reverse iteration. It should return a new iterator object that\n iterates over all the objects in the container in reverse order.\n\n If the ``__reversed__()`` method is not provided, the\n ``reversed()`` built-in will fall back to using the sequence\n protocol (``__len__()`` and ``__getitem__()``). Objects that\n support the sequence protocol should only provide\n ``__reversed__()`` if they can provide an implementation that is\n more efficient than the one provided by ``reversed()``.\n\nThe membership test operators (``in`` and ``not in``) are normally\nimplemented as an iteration through a sequence. However, container\nobjects can supply the following special method with a more efficient\nimplementation, which also does not require the object be a sequence.\n\nobject.__contains__(self, item)\n\n Called to implement membership test operators. Should return true\n if *item* is in *self*, false otherwise. For mapping objects, this\n should consider the keys of the mapping rather than the values or\n the key-item pairs.\n\n For objects that don\'t define ``__contains__()``, the membership\n test first tries iteration via ``__iter__()``, then the old\n sequence iteration protocol via ``__getitem__()``, see *this\n section in the language reference*.\n\n\nEmulating numeric types\n=======================\n\nThe following methods can be defined to emulate numeric objects.\nMethods corresponding to operations that are not supported by the\nparticular kind of number implemented (e.g., bitwise operations for\nnon-integral numbers) should be left undefined.\n\nobject.__add__(self, other)\nobject.__sub__(self, other)\nobject.__mul__(self, other)\nobject.__truediv__(self, other)\nobject.__floordiv__(self, other)\nobject.__mod__(self, other)\nobject.__divmod__(self, other)\nobject.__pow__(self, other[, modulo])\nobject.__lshift__(self, other)\nobject.__rshift__(self, other)\nobject.__and__(self, other)\nobject.__xor__(self, other)\nobject.__or__(self, other)\n\n These methods are called to implement the binary arithmetic\n operations (``+``, ``-``, ``*``, ``/``, ``//``, ``%``,\n ``divmod()``, ``pow()``, ``**``, ``<<``, ``>>``, ``&``, ``^``,\n ``|``). For instance, to evaluate the expression ``x + y``, where\n *x* is an instance of a class that has an ``__add__()`` method,\n ``x.__add__(y)`` is called. The ``__divmod__()`` method should be\n the equivalent to using ``__floordiv__()`` and ``__mod__()``; it\n should not be related to ``__truediv__()``. Note that\n ``__pow__()`` should be defined to accept an optional third\n argument if the ternary version of the built-in ``pow()`` function\n is to be supported.\n\n If one of those methods does not support the operation with the\n supplied arguments, it should return ``NotImplemented``.\n\nobject.__radd__(self, other)\nobject.__rsub__(self, other)\nobject.__rmul__(self, other)\nobject.__rtruediv__(self, other)\nobject.__rfloordiv__(self, other)\nobject.__rmod__(self, other)\nobject.__rdivmod__(self, other)\nobject.__rpow__(self, other)\nobject.__rlshift__(self, other)\nobject.__rrshift__(self, other)\nobject.__rand__(self, other)\nobject.__rxor__(self, other)\nobject.__ror__(self, other)\n\n These methods are called to implement the binary arithmetic\n operations (``+``, ``-``, ``*``, ``/``, ``//``, ``%``,\n ``divmod()``, ``pow()``, ``**``, ``<<``, ``>>``, ``&``, ``^``,\n ``|``) with reflected (swapped) operands. These functions are only\n called if the left operand does not support the corresponding\n operation and the operands are of different types. [2] For\n instance, to evaluate the expression ``x - y``, where *y* is an\n instance of a class that has an ``__rsub__()`` method,\n ``y.__rsub__(x)`` is called if ``x.__sub__(y)`` returns\n *NotImplemented*.\n\n Note that ternary ``pow()`` will not try calling ``__rpow__()``\n (the coercion rules would become too complicated).\n\n Note: If the right operand\'s type is a subclass of the left operand\'s\n type and that subclass provides the reflected method for the\n operation, this method will be called before the left operand\'s\n non-reflected method. This behavior allows subclasses to\n override their ancestors\' operations.\n\nobject.__iadd__(self, other)\nobject.__isub__(self, other)\nobject.__imul__(self, other)\nobject.__itruediv__(self, other)\nobject.__ifloordiv__(self, other)\nobject.__imod__(self, other)\nobject.__ipow__(self, other[, modulo])\nobject.__ilshift__(self, other)\nobject.__irshift__(self, other)\nobject.__iand__(self, other)\nobject.__ixor__(self, other)\nobject.__ior__(self, other)\n\n These methods are called to implement the augmented arithmetic\n assignments (``+=``, ``-=``, ``*=``, ``/=``, ``//=``, ``%=``,\n ``**=``, ``<<=``, ``>>=``, ``&=``, ``^=``, ``|=``). These methods\n should attempt to do the operation in-place (modifying *self*) and\n return the result (which could be, but does not have to be,\n *self*). If a specific method is not defined, the augmented\n assignment falls back to the normal methods. For instance, to\n execute the statement ``x += y``, where *x* is an instance of a\n class that has an ``__iadd__()`` method, ``x.__iadd__(y)`` is\n called. If *x* is an instance of a class that does not define a\n ``__iadd__()`` method, ``x.__add__(y)`` and ``y.__radd__(x)`` are\n considered, as with the evaluation of ``x + y``.\n\nobject.__neg__(self)\nobject.__pos__(self)\nobject.__abs__(self)\nobject.__invert__(self)\n\n Called to implement the unary arithmetic operations (``-``, ``+``,\n ``abs()`` and ``~``).\n\nobject.__complex__(self)\nobject.__int__(self)\nobject.__float__(self)\nobject.__round__(self[, n])\n\n Called to implement the built-in functions ``complex()``,\n ``int()``, ``float()`` and ``round()``. Should return a value of\n the appropriate type.\n\nobject.__index__(self)\n\n Called to implement ``operator.index()``. Also called whenever\n Python needs an integer object (such as in slicing, or in the\n built-in ``bin()``, ``hex()`` and ``oct()`` functions). Must return\n an integer.\n\n\nWith Statement Context Managers\n===============================\n\nA *context manager* is an object that defines the runtime context to\nbe established when executing a ``with`` statement. The context\nmanager handles the entry into, and the exit from, the desired runtime\ncontext for the execution of the block of code. Context managers are\nnormally invoked using the ``with`` statement (described in section\n*The with statement*), but can also be used by directly invoking their\nmethods.\n\nTypical uses of context managers include saving and restoring various\nkinds of global state, locking and unlocking resources, closing opened\nfiles, etc.\n\nFor more information on context managers, see *Context Manager Types*.\n\nobject.__enter__(self)\n\n Enter the runtime context related to this object. The ``with``\n statement will bind this method\'s return value to the target(s)\n specified in the ``as`` clause of the statement, if any.\n\nobject.__exit__(self, exc_type, exc_value, traceback)\n\n Exit the runtime context related to this object. The parameters\n describe the exception that caused the context to be exited. If the\n context was exited without an exception, all three arguments will\n be ``None``.\n\n If an exception is supplied, and the method wishes to suppress the\n exception (i.e., prevent it from being propagated), it should\n return a true value. Otherwise, the exception will be processed\n normally upon exit from this method.\n\n Note that ``__exit__()`` methods should not reraise the passed-in\n exception; this is the caller\'s responsibility.\n\nSee also:\n\n **PEP 0343** - The "with" statement\n The specification, background, and examples for the Python\n ``with`` statement.\n\n\nSpecial method lookup\n=====================\n\nFor custom classes, implicit invocations of special methods are only\nguaranteed to work correctly if defined on an object\'s type, not in\nthe object\'s instance dictionary. That behaviour is the reason why\nthe following code raises an exception:\n\n >>> class C:\n ... pass\n ...\n >>> c = C()\n >>> c.__len__ = lambda: 5\n >>> len(c)\n Traceback (most recent call last):\n File "", line 1, in \n TypeError: object of type \'C\' has no len()\n\nThe rationale behind this behaviour lies with a number of special\nmethods such as ``__hash__()`` and ``__repr__()`` that are implemented\nby all objects, including type objects. If the implicit lookup of\nthese methods used the conventional lookup process, they would fail\nwhen invoked on the type object itself:\n\n >>> 1 .__hash__() == hash(1)\n True\n >>> int.__hash__() == hash(int)\n Traceback (most recent call last):\n File "", line 1, in \n TypeError: descriptor \'__hash__\' of \'int\' object needs an argument\n\nIncorrectly attempting to invoke an unbound method of a class in this\nway is sometimes referred to as \'metaclass confusion\', and is avoided\nby bypassing the instance when looking up special methods:\n\n >>> type(1).__hash__(1) == hash(1)\n True\n >>> type(int).__hash__(int) == hash(int)\n True\n\nIn addition to bypassing any instance attributes in the interest of\ncorrectness, implicit special method lookup generally also bypasses\nthe ``__getattribute__()`` method even of the object\'s metaclass:\n\n >>> class Meta(type):\n ... def __getattribute__(*args):\n ... print("Metaclass getattribute invoked")\n ... return type.__getattribute__(*args)\n ...\n >>> class C(object, metaclass=Meta):\n ... def __len__(self):\n ... return 10\n ... def __getattribute__(*args):\n ... print("Class getattribute invoked")\n ... return object.__getattribute__(*args)\n ...\n >>> c = C()\n >>> c.__len__() # Explicit lookup via instance\n Class getattribute invoked\n 10\n >>> type(c).__len__(c) # Explicit lookup via type\n Metaclass getattribute invoked\n 10\n >>> len(c) # Implicit lookup\n 10\n\nBypassing the ``__getattribute__()`` machinery in this fashion\nprovides significant scope for speed optimisations within the\ninterpreter, at the cost of some flexibility in the handling of\nspecial methods (the special method *must* be set on the class object\nitself in order to be consistently invoked by the interpreter).\n\n-[ Footnotes ]-\n\n[1] It *is* possible in some cases to change an object\'s type, under\n certain controlled conditions. It generally isn\'t a good idea\n though, since it can lead to some very strange behaviour if it is\n handled incorrectly.\n\n[2] For operands of the same type, it is assumed that if the non-\n reflected method (such as ``__add__()``) fails the operation is\n not supported, which is why the reflected method is not called.\n', 'string-methods': '\nString Methods\n**************\n\nString objects support the methods listed below.\n\nIn addition, Python\'s strings support the sequence type methods\ndescribed in the *Sequence Types --- str, bytes, bytearray, list,\ntuple, range* section. To output formatted strings, see the *String\nFormatting* section. Also, see the ``re`` module for string functions\nbased on regular expressions.\n\nstr.capitalize()\n\n Return a copy of the string with its first character capitalized\n and the rest lowercased.\n\nstr.center(width[, fillchar])\n\n Return centered in a string of length *width*. Padding is done\n using the specified *fillchar* (default is a space).\n\nstr.count(sub[, start[, end]])\n\n Return the number of non-overlapping occurrences of substring *sub*\n in the range [*start*, *end*]. Optional arguments *start* and\n *end* are interpreted as in slice notation.\n\nstr.encode(encoding="utf-8", errors="strict")\n\n Return an encoded version of the string as a bytes object. Default\n encoding is ``\'utf-8\'``. *errors* may be given to set a different\n error handling scheme. The default for *errors* is ``\'strict\'``,\n meaning that encoding errors raise a ``UnicodeError``. Other\n possible values are ``\'ignore\'``, ``\'replace\'``,\n ``\'xmlcharrefreplace\'``, ``\'backslashreplace\'`` and any other name\n registered via ``codecs.register_error()``, see section *Codec Base\n Classes*. For a list of possible encodings, see section *Standard\n Encodings*.\n\n Changed in version 3.1: Support for keyword arguments added.\n\nstr.endswith(suffix[, start[, end]])\n\n Return ``True`` if the string ends with the specified *suffix*,\n otherwise return ``False``. *suffix* can also be a tuple of\n suffixes to look for. With optional *start*, test beginning at\n that position. With optional *end*, stop comparing at that\n position.\n\nstr.expandtabs([tabsize])\n\n Return a copy of the string where all tab characters are replaced\n by one or more spaces, depending on the current column and the\n given tab size. The column number is reset to zero after each\n newline occurring in the string. If *tabsize* is not given, a tab\n size of ``8`` characters is assumed. This doesn\'t understand other\n non-printing characters or escape sequences.\n\nstr.find(sub[, start[, end]])\n\n Return the lowest index in the string where substring *sub* is\n found, such that *sub* is contained in the slice ``s[start:end]``.\n Optional arguments *start* and *end* are interpreted as in slice\n notation. Return ``-1`` if *sub* is not found.\n\nstr.format(*args, **kwargs)\n\n Perform a string formatting operation. The string on which this\n method is called can contain literal text or replacement fields\n delimited by braces ``{}``. Each replacement field contains either\n the numeric index of a positional argument, or the name of a\n keyword argument. Returns a copy of the string where each\n replacement field is replaced with the string value of the\n corresponding argument.\n\n >>> "The sum of 1 + 2 is {0}".format(1+2)\n \'The sum of 1 + 2 is 3\'\n\n See *Format String Syntax* for a description of the various\n formatting options that can be specified in format strings.\n\nstr.format_map(mapping)\n\n Similar to ``str.format(**mapping)``, except that ``mapping`` is\n used directly and not copied to a ``dict`` . This is useful if for\n example ``mapping`` is a dict subclass:\n\n >>> class Default(dict):\n ... def __missing__(self, key):\n ... return key\n ...\n >>> \'{name} was born in {country}\'.format_map(Default(name=\'Guido\'))\n \'Guido was born in country\'\n\n New in version 3.2.\n\nstr.index(sub[, start[, end]])\n\n Like ``find()``, but raise ``ValueError`` when the substring is not\n found.\n\nstr.isalnum()\n\n Return true if all characters in the string are alphanumeric and\n there is at least one character, false otherwise. A character\n ``c`` is alphanumeric if one of the following returns ``True``:\n ``c.isalpha()``, ``c.isdecimal()``, ``c.isdigit()``, or\n ``c.isnumeric()``.\n\nstr.isalpha()\n\n Return true if all characters in the string are alphabetic and\n there is at least one character, false otherwise. Alphabetic\n characters are those characters defined in the Unicode character\n database as "Letter", i.e., those with general category property\n being one of "Lm", "Lt", "Lu", "Ll", or "Lo". Note that this is\n different from the "Alphabetic" property defined in the Unicode\n Standard.\n\nstr.isdecimal()\n\n Return true if all characters in the string are decimal characters\n and there is at least one character, false otherwise. Decimal\n characters are those from general category "Nd". This category\n includes digit characters, and all characters that that can be used\n to form decimal-radix numbers, e.g. U+0660, ARABIC-INDIC DIGIT\n ZERO.\n\nstr.isdigit()\n\n Return true if all characters in the string are digits and there is\n at least one character, false otherwise. Digits include decimal\n characters and digits that need special handling, such as the\n compatibility superscript digits. Formally, a digit is a character\n that has the property value Numeric_Type=Digit or\n Numeric_Type=Decimal.\n\nstr.isidentifier()\n\n Return true if the string is a valid identifier according to the\n language definition, section *Identifiers and keywords*.\n\nstr.islower()\n\n Return true if all cased characters in the string are lowercase and\n there is at least one cased character, false otherwise. Cased\n characters are those with general category property being one of\n "Lu", "Ll", or "Lt" and lowercase characters are those with general\n category property "Ll".\n\nstr.isnumeric()\n\n Return true if all characters in the string are numeric characters,\n and there is at least one character, false otherwise. Numeric\n characters include digit characters, and all characters that have\n the Unicode numeric value property, e.g. U+2155, VULGAR FRACTION\n ONE FIFTH. Formally, numeric characters are those with the\n property value Numeric_Type=Digit, Numeric_Type=Decimal or\n Numeric_Type=Numeric.\n\nstr.isprintable()\n\n Return true if all characters in the string are printable or the\n string is empty, false otherwise. Nonprintable characters are\n those characters defined in the Unicode character database as\n "Other" or "Separator", excepting the ASCII space (0x20) which is\n considered printable. (Note that printable characters in this\n context are those which should not be escaped when ``repr()`` is\n invoked on a string. It has no bearing on the handling of strings\n written to ``sys.stdout`` or ``sys.stderr``.)\n\nstr.isspace()\n\n Return true if there are only whitespace characters in the string\n and there is at least one character, false otherwise. Whitespace\n characters are those characters defined in the Unicode character\n database as "Other" or "Separator" and those with bidirectional\n property being one of "WS", "B", or "S".\n\nstr.istitle()\n\n Return true if the string is a titlecased string and there is at\n least one character, for example uppercase characters may only\n follow uncased characters and lowercase characters only cased ones.\n Return false otherwise.\n\nstr.isupper()\n\n Return true if all cased characters in the string are uppercase and\n there is at least one cased character, false otherwise. Cased\n characters are those with general category property being one of\n "Lu", "Ll", or "Lt" and uppercase characters are those with general\n category property "Lu".\n\nstr.join(iterable)\n\n Return a string which is the concatenation of the strings in the\n *iterable* *iterable*. A ``TypeError`` will be raised if there are\n any non-string values in *seq*, including ``bytes`` objects. The\n separator between elements is the string providing this method.\n\nstr.ljust(width[, fillchar])\n\n Return the string left justified in a string of length *width*.\n Padding is done using the specified *fillchar* (default is a\n space). The original string is returned if *width* is less than\n ``len(s)``.\n\nstr.lower()\n\n Return a copy of the string converted to lowercase.\n\nstr.lstrip([chars])\n\n Return a copy of the string with leading characters removed. The\n *chars* argument is a string specifying the set of characters to be\n removed. If omitted or ``None``, the *chars* argument defaults to\n removing whitespace. The *chars* argument is not a prefix; rather,\n all combinations of its values are stripped:\n\n >>> \' spacious \'.lstrip()\n \'spacious \'\n >>> \'www.example.com\'.lstrip(\'cmowz.\')\n \'example.com\'\n\nstatic str.maketrans(x[, y[, z]])\n\n This static method returns a translation table usable for\n ``str.translate()``.\n\n If there is only one argument, it must be a dictionary mapping\n Unicode ordinals (integers) or characters (strings of length 1) to\n Unicode ordinals, strings (of arbitrary lengths) or None.\n Character keys will then be converted to ordinals.\n\n If there are two arguments, they must be strings of equal length,\n and in the resulting dictionary, each character in x will be mapped\n to the character at the same position in y. If there is a third\n argument, it must be a string, whose characters will be mapped to\n None in the result.\n\nstr.partition(sep)\n\n Split the string at the first occurrence of *sep*, and return a\n 3-tuple containing the part before the separator, the separator\n itself, and the part after the separator. If the separator is not\n found, return a 3-tuple containing the string itself, followed by\n two empty strings.\n\nstr.replace(old, new[, count])\n\n Return a copy of the string with all occurrences of substring *old*\n replaced by *new*. If the optional argument *count* is given, only\n the first *count* occurrences are replaced.\n\nstr.rfind(sub[, start[, end]])\n\n Return the highest index in the string where substring *sub* is\n found, such that *sub* is contained within ``s[start:end]``.\n Optional arguments *start* and *end* are interpreted as in slice\n notation. Return ``-1`` on failure.\n\nstr.rindex(sub[, start[, end]])\n\n Like ``rfind()`` but raises ``ValueError`` when the substring *sub*\n is not found.\n\nstr.rjust(width[, fillchar])\n\n Return the string right justified in a string of length *width*.\n Padding is done using the specified *fillchar* (default is a\n space). The original string is returned if *width* is less than\n ``len(s)``.\n\nstr.rpartition(sep)\n\n Split the string at the last occurrence of *sep*, and return a\n 3-tuple containing the part before the separator, the separator\n itself, and the part after the separator. If the separator is not\n found, return a 3-tuple containing two empty strings, followed by\n the string itself.\n\nstr.rsplit([sep[, maxsplit]])\n\n Return a list of the words in the string, using *sep* as the\n delimiter string. If *maxsplit* is given, at most *maxsplit* splits\n are done, the *rightmost* ones. If *sep* is not specified or\n ``None``, any whitespace string is a separator. Except for\n splitting from the right, ``rsplit()`` behaves like ``split()``\n which is described in detail below.\n\nstr.rstrip([chars])\n\n Return a copy of the string with trailing characters removed. The\n *chars* argument is a string specifying the set of characters to be\n removed. If omitted or ``None``, the *chars* argument defaults to\n removing whitespace. The *chars* argument is not a suffix; rather,\n all combinations of its values are stripped:\n\n >>> \' spacious \'.rstrip()\n \' spacious\'\n >>> \'mississippi\'.rstrip(\'ipz\')\n \'mississ\'\n\nstr.split([sep[, maxsplit]])\n\n Return a list of the words in the string, using *sep* as the\n delimiter string. If *maxsplit* is given, at most *maxsplit*\n splits are done (thus, the list will have at most ``maxsplit+1``\n elements). If *maxsplit* is not specified, then there is no limit\n on the number of splits (all possible splits are made).\n\n If *sep* is given, consecutive delimiters are not grouped together\n and are deemed to delimit empty strings (for example,\n ``\'1,,2\'.split(\',\')`` returns ``[\'1\', \'\', \'2\']``). The *sep*\n argument may consist of multiple characters (for example,\n ``\'1<>2<>3\'.split(\'<>\')`` returns ``[\'1\', \'2\', \'3\']``). Splitting\n an empty string with a specified separator returns ``[\'\']``.\n\n If *sep* is not specified or is ``None``, a different splitting\n algorithm is applied: runs of consecutive whitespace are regarded\n as a single separator, and the result will contain no empty strings\n at the start or end if the string has leading or trailing\n whitespace. Consequently, splitting an empty string or a string\n consisting of just whitespace with a ``None`` separator returns\n ``[]``.\n\n For example, ``\' 1 2 3 \'.split()`` returns ``[\'1\', \'2\', \'3\']``,\n and ``\' 1 2 3 \'.split(None, 1)`` returns ``[\'1\', \'2 3 \']``.\n\nstr.splitlines([keepends])\n\n Return a list of the lines in the string, breaking at line\n boundaries. Line breaks are not included in the resulting list\n unless *keepends* is given and true.\n\nstr.startswith(prefix[, start[, end]])\n\n Return ``True`` if string starts with the *prefix*, otherwise\n return ``False``. *prefix* can also be a tuple of prefixes to look\n for. With optional *start*, test string beginning at that\n position. With optional *end*, stop comparing string at that\n position.\n\nstr.strip([chars])\n\n Return a copy of the string with the leading and trailing\n characters removed. The *chars* argument is a string specifying the\n set of characters to be removed. If omitted or ``None``, the\n *chars* argument defaults to removing whitespace. The *chars*\n argument is not a prefix or suffix; rather, all combinations of its\n values are stripped:\n\n >>> \' spacious \'.strip()\n \'spacious\'\n >>> \'www.example.com\'.strip(\'cmowz.\')\n \'example\'\n\nstr.swapcase()\n\n Return a copy of the string with uppercase characters converted to\n lowercase and vice versa.\n\nstr.title()\n\n Return a titlecased version of the string where words start with an\n uppercase character and the remaining characters are lowercase.\n\n The algorithm uses a simple language-independent definition of a\n word as groups of consecutive letters. The definition works in\n many contexts but it means that apostrophes in contractions and\n possessives form word boundaries, which may not be the desired\n result:\n\n >>> "they\'re bill\'s friends from the UK".title()\n "They\'Re Bill\'S Friends From The Uk"\n\n A workaround for apostrophes can be constructed using regular\n expressions:\n\n >>> import re\n >>> def titlecase(s):\n return re.sub(r"[A-Za-z]+(\'[A-Za-z]+)?",\n lambda mo: mo.group(0)[0].upper() +\n mo.group(0)[1:].lower(),\n s)\n\n >>> titlecase("they\'re bill\'s friends.")\n "They\'re Bill\'s Friends."\n\nstr.translate(map)\n\n Return a copy of the *s* where all characters have been mapped\n through the *map* which must be a dictionary of Unicode ordinals\n (integers) to Unicode ordinals, strings or ``None``. Unmapped\n characters are left untouched. Characters mapped to ``None`` are\n deleted.\n\n You can use ``str.maketrans()`` to create a translation map from\n character-to-character mappings in different formats.\n\n Note: An even more flexible approach is to create a custom character\n mapping codec using the ``codecs`` module (see\n ``encodings.cp1251`` for an example).\n\nstr.upper()\n\n Return a copy of the string converted to uppercase.\n\nstr.zfill(width)\n\n Return the numeric string left filled with zeros in a string of\n length *width*. A sign prefix is handled correctly. The original\n string is returned if *width* is less than ``len(s)``.\n', 'strings': '\nString and Bytes literals\n*************************\n\nString literals are described by the following lexical definitions:\n\n stringliteral ::= [stringprefix](shortstring | longstring)\n stringprefix ::= "r" | "R"\n shortstring ::= "\'" shortstringitem* "\'" | \'"\' shortstringitem* \'"\'\n longstring ::= "\'\'\'" longstringitem* "\'\'\'" | \'"""\' longstringitem* \'"""\'\n shortstringitem ::= shortstringchar | stringescapeseq\n longstringitem ::= longstringchar | stringescapeseq\n shortstringchar ::= \n longstringchar ::= \n stringescapeseq ::= "\\" \n\n bytesliteral ::= bytesprefix(shortbytes | longbytes)\n bytesprefix ::= "b" | "B" | "br" | "Br" | "bR" | "BR"\n shortbytes ::= "\'" shortbytesitem* "\'" | \'"\' shortbytesitem* \'"\'\n longbytes ::= "\'\'\'" longbytesitem* "\'\'\'" | \'"""\' longbytesitem* \'"""\'\n shortbytesitem ::= shortbyteschar | bytesescapeseq\n longbytesitem ::= longbyteschar | bytesescapeseq\n shortbyteschar ::= \n longbyteschar ::= \n bytesescapeseq ::= "\\" \n\nOne syntactic restriction not indicated by these productions is that\nwhitespace is not allowed between the ``stringprefix`` or\n``bytesprefix`` and the rest of the literal. The source character set\nis defined by the encoding declaration; it is UTF-8 if no encoding\ndeclaration is given in the source file; see section *Encoding\ndeclarations*.\n\nIn plain English: Both types of literals can be enclosed in matching\nsingle quotes (``\'``) or double quotes (``"``). They can also be\nenclosed in matching groups of three single or double quotes (these\nare generally referred to as *triple-quoted strings*). The backslash\n(``\\``) character is used to escape characters that otherwise have a\nspecial meaning, such as newline, backslash itself, or the quote\ncharacter.\n\nBytes literals are always prefixed with ``\'b\'`` or ``\'B\'``; they\nproduce an instance of the ``bytes`` type instead of the ``str`` type.\nThey may only contain ASCII characters; bytes with a numeric value of\n128 or greater must be expressed with escapes.\n\nBoth string and bytes literals may optionally be prefixed with a\nletter ``\'r\'`` or ``\'R\'``; such strings are called *raw strings* and\ntreat backslashes as literal characters. As a result, in string\nliterals, ``\'\\U\'`` and ``\'\\u\'`` escapes in raw strings are not treated\nspecially.\n\nIn triple-quoted strings, unescaped newlines and quotes are allowed\n(and are retained), except that three unescaped quotes in a row\nterminate the string. (A "quote" is the character used to open the\nstring, i.e. either ``\'`` or ``"``.)\n\nUnless an ``\'r\'`` or ``\'R\'`` prefix is present, escape sequences in\nstrings are interpreted according to rules similar to those used by\nStandard C. The recognized escape sequences are:\n\n+-------------------+-----------------------------------+---------+\n| Escape Sequence | Meaning | Notes |\n+===================+===================================+=========+\n| ``\\newline`` | Backslash and newline ignored | |\n+-------------------+-----------------------------------+---------+\n| ``\\\\`` | Backslash (``\\``) | |\n+-------------------+-----------------------------------+---------+\n| ``\\\'`` | Single quote (``\'``) | |\n+-------------------+-----------------------------------+---------+\n| ``\\"`` | Double quote (``"``) | |\n+-------------------+-----------------------------------+---------+\n| ``\\a`` | ASCII Bell (BEL) | |\n+-------------------+-----------------------------------+---------+\n| ``\\b`` | ASCII Backspace (BS) | |\n+-------------------+-----------------------------------+---------+\n| ``\\f`` | ASCII Formfeed (FF) | |\n+-------------------+-----------------------------------+---------+\n| ``\\n`` | ASCII Linefeed (LF) | |\n+-------------------+-----------------------------------+---------+\n| ``\\r`` | ASCII Carriage Return (CR) | |\n+-------------------+-----------------------------------+---------+\n| ``\\t`` | ASCII Horizontal Tab (TAB) | |\n+-------------------+-----------------------------------+---------+\n| ``\\v`` | ASCII Vertical Tab (VT) | |\n+-------------------+-----------------------------------+---------+\n| ``\\ooo`` | Character with octal value *ooo* | (1,3) |\n+-------------------+-----------------------------------+---------+\n| ``\\xhh`` | Character with hex value *hh* | (2,3) |\n+-------------------+-----------------------------------+---------+\n\nEscape sequences only recognized in string literals are:\n\n+-------------------+-----------------------------------+---------+\n| Escape Sequence | Meaning | Notes |\n+===================+===================================+=========+\n| ``\\N{name}`` | Character named *name* in the | |\n| | Unicode database | |\n+-------------------+-----------------------------------+---------+\n| ``\\uxxxx`` | Character with 16-bit hex value | (4) |\n| | *xxxx* | |\n+-------------------+-----------------------------------+---------+\n| ``\\Uxxxxxxxx`` | Character with 32-bit hex value | (5) |\n| | *xxxxxxxx* | |\n+-------------------+-----------------------------------+---------+\n\nNotes:\n\n1. As in Standard C, up to three octal digits are accepted.\n\n2. Unlike in Standard C, exactly two hex digits are required.\n\n3. In a bytes literal, hexadecimal and octal escapes denote the byte\n with the given value. In a string literal, these escapes denote a\n Unicode character with the given value.\n\n4. Individual code units which form parts of a surrogate pair can be\n encoded using this escape sequence. Exactly four hex digits are\n required.\n\n5. Any Unicode character can be encoded this way, but characters\n outside the Basic Multilingual Plane (BMP) will be encoded using a\n surrogate pair if Python is compiled to use 16-bit code units (the\n default). Exactly eight hex digits are required.\n\nUnlike Standard C, all unrecognized escape sequences are left in the\nstring unchanged, i.e., *the backslash is left in the string*. (This\nbehavior is useful when debugging: if an escape sequence is mistyped,\nthe resulting output is more easily recognized as broken.) It is also\nimportant to note that the escape sequences only recognized in string\nliterals fall into the category of unrecognized escapes for bytes\nliterals.\n\nEven in a raw string, string quotes can be escaped with a backslash,\nbut the backslash remains in the string; for example, ``r"\\""`` is a\nvalid string literal consisting of two characters: a backslash and a\ndouble quote; ``r"\\"`` is not a valid string literal (even a raw\nstring cannot end in an odd number of backslashes). Specifically, *a\nraw string cannot end in a single backslash* (since the backslash\nwould escape the following quote character). Note also that a single\nbackslash followed by a newline is interpreted as those two characters\nas part of the string, *not* as a line continuation.\n', 'subscriptions': '\nSubscriptions\n*************\n\nA subscription selects an item of a sequence (string, tuple or list)\nor mapping (dictionary) object:\n\n subscription ::= primary "[" expression_list "]"\n\nThe primary must evaluate to an object that supports subscription,\ne.g. a list or dictionary. User-defined objects can support\nsubscription by defining a ``__getitem__()`` method.\n\nFor built-in objects, there are two types of objects that support\nsubscription:\n\nIf the primary is a mapping, the expression list must evaluate to an\nobject whose value is one of the keys of the mapping, and the\nsubscription selects the value in the mapping that corresponds to that\nkey. (The expression list is a tuple except if it has exactly one\nitem.)\n\nIf the primary is a sequence, the expression (list) must evaluate to\nan integer or a slice (as discussed in the following section).\n\nThe formal syntax makes no special provision for negative indices in\nsequences; however, built-in sequences all provide a ``__getitem__()``\nmethod that interprets negative indices by adding the length of the\nsequence to the index (so that ``x[-1]`` selects the last item of\n``x``). The resulting value must be a nonnegative integer less than\nthe number of items in the sequence, and the subscription selects the\nitem whose index is that value (counting from zero). Since the support\nfor negative indices and slicing occurs in the object\'s\n``__getitem__()`` method, subclasses overriding this method will need\nto explicitly add that support.\n\nA string\'s items are characters. A character is not a separate data\ntype but a string of exactly one character.\n', diff --git a/Lib/test/test_pydoc.py b/Lib/test/test_pydoc.py --- a/Lib/test/test_pydoc.py +++ b/Lib/test/test_pydoc.py @@ -3,6 +3,7 @@ import difflib import inspect import pydoc +import keyword import re import string import subprocess @@ -465,11 +466,17 @@ self.assertEqual(result, title) +class TestHelper(unittest.TestCase): + def test_keywords(self): + self.assertEqual(sorted(pydoc.Helper.keywords), + sorted(keyword.kwlist)) + def test_main(): test.support.run_unittest(PydocDocTest, TestDescriptions, PydocServerTest, PydocUrlHandlerTest, + TestHelper, ) if __name__ == "__main__": -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Apr 28 06:59:52 2011 From: python-checkins at python.org (ezio.melotti) Date: Thu, 28 Apr 2011 06:59:52 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): #11926: merge with 3.2. Message-ID: http://hg.python.org/cpython/rev/0d8a6833f5be changeset: 69651:0d8a6833f5be parent: 69647:618642ba7551 parent: 69650:7b4c853aa07d user: Ezio Melotti date: Thu Apr 28 07:55:29 2011 +0300 summary: #11926: merge with 3.2. files: Lib/pydoc.py | 6 ++++++ Lib/pydoc_data/topics.py | 24 ++++++++++++------------ Lib/test/test_pydoc.py | 7 +++++++ 3 files changed, 25 insertions(+), 12 deletions(-) diff --git a/Lib/pydoc.py b/Lib/pydoc.py --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -1579,6 +1579,9 @@ # in Doc/ and copying the output file into the Lib/ directory. keywords = { + 'False': '', + 'None': '', + 'True': '', 'and': 'BOOLEAN', 'as': 'with', 'assert': ('assert', ''), @@ -1794,6 +1797,9 @@ elif request[:8] == 'modules ': self.listmodules(request.split()[1]) elif request in self.symbols: self.showsymbol(request) + elif request in ['True', 'False', 'None']: + # special case these keywords since they are objects too + doc(eval(request), 'Help on %s:') elif request in self.keywords: self.showtopic(request) elif request in self.topics: self.showtopic(request) elif request: doc(request, 'Help on %s:', output=self._output) diff --git a/Lib/pydoc_data/topics.py b/Lib/pydoc_data/topics.py --- a/Lib/pydoc_data/topics.py +++ b/Lib/pydoc_data/topics.py @@ -1,9 +1,9 @@ -# Autogenerated by Sphinx on Sun Feb 20 10:16:17 2011 +# Autogenerated by Sphinx on Thu Apr 28 07:53:12 2011 topics = {'assert': '\nThe ``assert`` statement\n************************\n\nAssert statements are a convenient way to insert debugging assertions\ninto a program:\n\n assert_stmt ::= "assert" expression ["," expression]\n\nThe simple form, ``assert expression``, is equivalent to\n\n if __debug__:\n if not expression: raise AssertionError\n\nThe extended form, ``assert expression1, expression2``, is equivalent\nto\n\n if __debug__:\n if not expression1: raise AssertionError(expression2)\n\nThese equivalences assume that ``__debug__`` and ``AssertionError``\nrefer to the built-in variables with those names. In the current\nimplementation, the built-in variable ``__debug__`` is ``True`` under\nnormal circumstances, ``False`` when optimization is requested\n(command line option -O). The current code generator emits no code\nfor an assert statement when optimization is requested at compile\ntime. Note that it is unnecessary to include the source code for the\nexpression that failed in the error message; it will be displayed as\npart of the stack trace.\n\nAssignments to ``__debug__`` are illegal. The value for the built-in\nvariable is determined when the interpreter starts.\n', - 'assignment': '\nAssignment statements\n*********************\n\nAssignment statements are used to (re)bind names to values and to\nmodify attributes or items of mutable objects:\n\n assignment_stmt ::= (target_list "=")+ (expression_list | yield_expression)\n target_list ::= target ("," target)* [","]\n target ::= identifier\n | "(" target_list ")"\n | "[" target_list "]"\n | attributeref\n | subscription\n | slicing\n | "*" target\n\n(See section *Primaries* for the syntax definitions for the last three\nsymbols.)\n\nAn assignment statement evaluates the expression list (remember that\nthis can be a single expression or a comma-separated list, the latter\nyielding a tuple) and assigns the single resulting object to each of\nthe target lists, from left to right.\n\nAssignment is defined recursively depending on the form of the target\n(list). When a target is part of a mutable object (an attribute\nreference, subscription or slicing), the mutable object must\nultimately perform the assignment and decide about its validity, and\nmay raise an exception if the assignment is unacceptable. The rules\nobserved by various types and the exceptions raised are given with the\ndefinition of the object types (see section *The standard type\nhierarchy*).\n\nAssignment of an object to a target list, optionally enclosed in\nparentheses or square brackets, is recursively defined as follows.\n\n* If the target list is a single target: The object is assigned to\n that target.\n\n* If the target list is a comma-separated list of targets: The object\n must be an iterable with the same number of items as there are\n targets in the target list, and the items are assigned, from left to\n right, to the corresponding targets. (This rule is relaxed as of\n Python 1.5; in earlier versions, the object had to be a tuple.\n Since strings are sequences, an assignment like ``a, b = "xy"`` is\n now legal as long as the string has the right length.)\n\n * If the target list contains one target prefixed with an asterisk,\n called a "starred" target: The object must be a sequence with at\n least as many items as there are targets in the target list, minus\n one. The first items of the sequence are assigned, from left to\n right, to the targets before the starred target. The final items\n of the sequence are assigned to the targets after the starred\n target. A list of the remaining items in the sequence is then\n assigned to the starred target (the list can be empty).\n\n * Else: The object must be a sequence with the same number of items\n as there are targets in the target list, and the items are\n assigned, from left to right, to the corresponding targets.\n\nAssignment of an object to a single target is recursively defined as\nfollows.\n\n* If the target is an identifier (name):\n\n * If the name does not occur in a ``global`` or ``nonlocal``\n statement in the current code block: the name is bound to the\n object in the current local namespace.\n\n * Otherwise: the name is bound to the object in the global namespace\n or the outer namespace determined by ``nonlocal``, respectively.\n\n The name is rebound if it was already bound. This may cause the\n reference count for the object previously bound to the name to reach\n zero, causing the object to be deallocated and its destructor (if it\n has one) to be called.\n\n* If the target is a target list enclosed in parentheses or in square\n brackets: The object must be an iterable with the same number of\n items as there are targets in the target list, and its items are\n assigned, from left to right, to the corresponding targets.\n\n* If the target is an attribute reference: The primary expression in\n the reference is evaluated. It should yield an object with\n assignable attributes; if this is not the case, ``TypeError`` is\n raised. That object is then asked to assign the assigned object to\n the given attribute; if it cannot perform the assignment, it raises\n an exception (usually but not necessarily ``AttributeError``).\n\n Note: If the object is a class instance and the attribute reference\n occurs on both sides of the assignment operator, the RHS expression,\n ``a.x`` can access either an instance attribute or (if no instance\n attribute exists) a class attribute. The LHS target ``a.x`` is\n always set as an instance attribute, creating it if necessary.\n Thus, the two occurrences of ``a.x`` do not necessarily refer to the\n same attribute: if the RHS expression refers to a class attribute,\n the LHS creates a new instance attribute as the target of the\n assignment:\n\n class Cls:\n x = 3 # class variable\n inst = Cls()\n inst.x = inst.x + 1 # writes inst.x as 4 leaving Cls.x as 3\n\n This description does not necessarily apply to descriptor\n attributes, such as properties created with ``property()``.\n\n* If the target is a subscription: The primary expression in the\n reference is evaluated. It should yield either a mutable sequence\n object (such as a list) or a mapping object (such as a dictionary).\n Next, the subscript expression is evaluated.\n\n If the primary is a mutable sequence object (such as a list), the\n subscript must yield an integer. If it is negative, the sequence\'s\n length is added to it. The resulting value must be a nonnegative\n integer less than the sequence\'s length, and the sequence is asked\n to assign the assigned object to its item with that index. If the\n index is out of range, ``IndexError`` is raised (assignment to a\n subscripted sequence cannot add new items to a list).\n\n If the primary is a mapping object (such as a dictionary), the\n subscript must have a type compatible with the mapping\'s key type,\n and the mapping is then asked to create a key/datum pair which maps\n the subscript to the assigned object. This can either replace an\n existing key/value pair with the same key value, or insert a new\n key/value pair (if no key with the same value existed).\n\n For user-defined objects, the ``__setitem__()`` method is called\n with appropriate arguments.\n\n* If the target is a slicing: The primary expression in the reference\n is evaluated. It should yield a mutable sequence object (such as a\n list). The assigned object should be a sequence object of the same\n type. Next, the lower and upper bound expressions are evaluated,\n insofar they are present; defaults are zero and the sequence\'s\n length. The bounds should evaluate to integers. If either bound is\n negative, the sequence\'s length is added to it. The resulting\n bounds are clipped to lie between zero and the sequence\'s length,\n inclusive. Finally, the sequence object is asked to replace the\n slice with the items of the assigned sequence. The length of the\n slice may be different from the length of the assigned sequence,\n thus changing the length of the target sequence, if the object\n allows it.\n\n**CPython implementation detail:** In the current implementation, the\nsyntax for targets is taken to be the same as for expressions, and\ninvalid syntax is rejected during the code generation phase, causing\nless detailed error messages.\n\nWARNING: Although the definition of assignment implies that overlaps\nbetween the left-hand side and the right-hand side are \'safe\' (for\nexample ``a, b = b, a`` swaps two variables), overlaps *within* the\ncollection of assigned-to variables are not safe! For instance, the\nfollowing program prints ``[0, 2]``:\n\n x = [0, 1]\n i = 0\n i, x[i] = 1, 2\n print(x)\n\nSee also:\n\n **PEP 3132** - Extended Iterable Unpacking\n The specification for the ``*target`` feature.\n\n\nAugmented assignment statements\n===============================\n\nAugmented assignment is the combination, in a single statement, of a\nbinary operation and an assignment statement:\n\n augmented_assignment_stmt ::= augtarget augop (expression_list | yield_expression)\n augtarget ::= identifier | attributeref | subscription | slicing\n augop ::= "+=" | "-=" | "*=" | "/=" | "//=" | "%=" | "**="\n | ">>=" | "<<=" | "&=" | "^=" | "|="\n\n(See section *Primaries* for the syntax definitions for the last three\nsymbols.)\n\nAn augmented assignment evaluates the target (which, unlike normal\nassignment statements, cannot be an unpacking) and the expression\nlist, performs the binary operation specific to the type of assignment\non the two operands, and assigns the result to the original target.\nThe target is only evaluated once.\n\nAn augmented assignment expression like ``x += 1`` can be rewritten as\n``x = x + 1`` to achieve a similar, but not exactly equal effect. In\nthe augmented version, ``x`` is only evaluated once. Also, when\npossible, the actual operation is performed *in-place*, meaning that\nrather than creating a new object and assigning that to the target,\nthe old object is modified instead.\n\nWith the exception of assigning to tuples and multiple targets in a\nsingle statement, the assignment done by augmented assignment\nstatements is handled the same way as normal assignments. Similarly,\nwith the exception of the possible *in-place* behavior, the binary\noperation performed by augmented assignment is the same as the normal\nbinary operations.\n\nFor targets which are attribute references, the same *caveat about\nclass and instance attributes* applies as for regular assignments.\n', + 'assignment': '\nAssignment statements\n*********************\n\nAssignment statements are used to (re)bind names to values and to\nmodify attributes or items of mutable objects:\n\n assignment_stmt ::= (target_list "=")+ (expression_list | yield_expression)\n target_list ::= target ("," target)* [","]\n target ::= identifier\n | "(" target_list ")"\n | "[" target_list "]"\n | attributeref\n | subscription\n | slicing\n | "*" target\n\n(See section *Primaries* for the syntax definitions for the last three\nsymbols.)\n\nAn assignment statement evaluates the expression list (remember that\nthis can be a single expression or a comma-separated list, the latter\nyielding a tuple) and assigns the single resulting object to each of\nthe target lists, from left to right.\n\nAssignment is defined recursively depending on the form of the target\n(list). When a target is part of a mutable object (an attribute\nreference, subscription or slicing), the mutable object must\nultimately perform the assignment and decide about its validity, and\nmay raise an exception if the assignment is unacceptable. The rules\nobserved by various types and the exceptions raised are given with the\ndefinition of the object types (see section *The standard type\nhierarchy*).\n\nAssignment of an object to a target list, optionally enclosed in\nparentheses or square brackets, is recursively defined as follows.\n\n* If the target list is a single target: The object is assigned to\n that target.\n\n* If the target list is a comma-separated list of targets: The object\n must be an iterable with the same number of items as there are\n targets in the target list, and the items are assigned, from left to\n right, to the corresponding targets.\n\n * If the target list contains one target prefixed with an asterisk,\n called a "starred" target: The object must be a sequence with at\n least as many items as there are targets in the target list, minus\n one. The first items of the sequence are assigned, from left to\n right, to the targets before the starred target. The final items\n of the sequence are assigned to the targets after the starred\n target. A list of the remaining items in the sequence is then\n assigned to the starred target (the list can be empty).\n\n * Else: The object must be a sequence with the same number of items\n as there are targets in the target list, and the items are\n assigned, from left to right, to the corresponding targets.\n\nAssignment of an object to a single target is recursively defined as\nfollows.\n\n* If the target is an identifier (name):\n\n * If the name does not occur in a ``global`` or ``nonlocal``\n statement in the current code block: the name is bound to the\n object in the current local namespace.\n\n * Otherwise: the name is bound to the object in the global namespace\n or the outer namespace determined by ``nonlocal``, respectively.\n\n The name is rebound if it was already bound. This may cause the\n reference count for the object previously bound to the name to reach\n zero, causing the object to be deallocated and its destructor (if it\n has one) to be called.\n\n* If the target is a target list enclosed in parentheses or in square\n brackets: The object must be an iterable with the same number of\n items as there are targets in the target list, and its items are\n assigned, from left to right, to the corresponding targets.\n\n* If the target is an attribute reference: The primary expression in\n the reference is evaluated. It should yield an object with\n assignable attributes; if this is not the case, ``TypeError`` is\n raised. That object is then asked to assign the assigned object to\n the given attribute; if it cannot perform the assignment, it raises\n an exception (usually but not necessarily ``AttributeError``).\n\n Note: If the object is a class instance and the attribute reference\n occurs on both sides of the assignment operator, the RHS expression,\n ``a.x`` can access either an instance attribute or (if no instance\n attribute exists) a class attribute. The LHS target ``a.x`` is\n always set as an instance attribute, creating it if necessary.\n Thus, the two occurrences of ``a.x`` do not necessarily refer to the\n same attribute: if the RHS expression refers to a class attribute,\n the LHS creates a new instance attribute as the target of the\n assignment:\n\n class Cls:\n x = 3 # class variable\n inst = Cls()\n inst.x = inst.x + 1 # writes inst.x as 4 leaving Cls.x as 3\n\n This description does not necessarily apply to descriptor\n attributes, such as properties created with ``property()``.\n\n* If the target is a subscription: The primary expression in the\n reference is evaluated. It should yield either a mutable sequence\n object (such as a list) or a mapping object (such as a dictionary).\n Next, the subscript expression is evaluated.\n\n If the primary is a mutable sequence object (such as a list), the\n subscript must yield an integer. If it is negative, the sequence\'s\n length is added to it. The resulting value must be a nonnegative\n integer less than the sequence\'s length, and the sequence is asked\n to assign the assigned object to its item with that index. If the\n index is out of range, ``IndexError`` is raised (assignment to a\n subscripted sequence cannot add new items to a list).\n\n If the primary is a mapping object (such as a dictionary), the\n subscript must have a type compatible with the mapping\'s key type,\n and the mapping is then asked to create a key/datum pair which maps\n the subscript to the assigned object. This can either replace an\n existing key/value pair with the same key value, or insert a new\n key/value pair (if no key with the same value existed).\n\n For user-defined objects, the ``__setitem__()`` method is called\n with appropriate arguments.\n\n* If the target is a slicing: The primary expression in the reference\n is evaluated. It should yield a mutable sequence object (such as a\n list). The assigned object should be a sequence object of the same\n type. Next, the lower and upper bound expressions are evaluated,\n insofar they are present; defaults are zero and the sequence\'s\n length. The bounds should evaluate to integers. If either bound is\n negative, the sequence\'s length is added to it. The resulting\n bounds are clipped to lie between zero and the sequence\'s length,\n inclusive. Finally, the sequence object is asked to replace the\n slice with the items of the assigned sequence. The length of the\n slice may be different from the length of the assigned sequence,\n thus changing the length of the target sequence, if the object\n allows it.\n\n**CPython implementation detail:** In the current implementation, the\nsyntax for targets is taken to be the same as for expressions, and\ninvalid syntax is rejected during the code generation phase, causing\nless detailed error messages.\n\nWARNING: Although the definition of assignment implies that overlaps\nbetween the left-hand side and the right-hand side are \'safe\' (for\nexample ``a, b = b, a`` swaps two variables), overlaps *within* the\ncollection of assigned-to variables are not safe! For instance, the\nfollowing program prints ``[0, 2]``:\n\n x = [0, 1]\n i = 0\n i, x[i] = 1, 2\n print(x)\n\nSee also:\n\n **PEP 3132** - Extended Iterable Unpacking\n The specification for the ``*target`` feature.\n\n\nAugmented assignment statements\n===============================\n\nAugmented assignment is the combination, in a single statement, of a\nbinary operation and an assignment statement:\n\n augmented_assignment_stmt ::= augtarget augop (expression_list | yield_expression)\n augtarget ::= identifier | attributeref | subscription | slicing\n augop ::= "+=" | "-=" | "*=" | "/=" | "//=" | "%=" | "**="\n | ">>=" | "<<=" | "&=" | "^=" | "|="\n\n(See section *Primaries* for the syntax definitions for the last three\nsymbols.)\n\nAn augmented assignment evaluates the target (which, unlike normal\nassignment statements, cannot be an unpacking) and the expression\nlist, performs the binary operation specific to the type of assignment\non the two operands, and assigns the result to the original target.\nThe target is only evaluated once.\n\nAn augmented assignment expression like ``x += 1`` can be rewritten as\n``x = x + 1`` to achieve a similar, but not exactly equal effect. In\nthe augmented version, ``x`` is only evaluated once. Also, when\npossible, the actual operation is performed *in-place*, meaning that\nrather than creating a new object and assigning that to the target,\nthe old object is modified instead.\n\nWith the exception of assigning to tuples and multiple targets in a\nsingle statement, the assignment done by augmented assignment\nstatements is handled the same way as normal assignments. Similarly,\nwith the exception of the possible *in-place* behavior, the binary\noperation performed by augmented assignment is the same as the normal\nbinary operations.\n\nFor targets which are attribute references, the same *caveat about\nclass and instance attributes* applies as for regular assignments.\n', 'atom-identifiers': '\nIdentifiers (Names)\n*******************\n\nAn identifier occurring as an atom is a name. See section\n*Identifiers and keywords* for lexical definition and section *Naming\nand binding* for documentation of naming and binding.\n\nWhen the name is bound to an object, evaluation of the atom yields\nthat object. When a name is not bound, an attempt to evaluate it\nraises a ``NameError`` exception.\n\n**Private name mangling:** When an identifier that textually occurs in\na class definition begins with two or more underscore characters and\ndoes not end in two or more underscores, it is considered a *private\nname* of that class. Private names are transformed to a longer form\nbefore code is generated for them. The transformation inserts the\nclass name in front of the name, with leading underscores removed, and\na single underscore inserted in front of the class name. For example,\nthe identifier ``__spam`` occurring in a class named ``Ham`` will be\ntransformed to ``_Ham__spam``. This transformation is independent of\nthe syntactical context in which the identifier is used. If the\ntransformed name is extremely long (longer than 255 characters),\nimplementation defined truncation may happen. If the class name\nconsists only of underscores, no transformation is done.\n', 'atom-literals': "\nLiterals\n********\n\nPython supports string and bytes literals and various numeric\nliterals:\n\n literal ::= stringliteral | bytesliteral\n | integer | floatnumber | imagnumber\n\nEvaluation of a literal yields an object of the given type (string,\nbytes, integer, floating point number, complex number) with the given\nvalue. The value may be approximated in the case of floating point\nand imaginary (complex) literals. See section *Literals* for details.\n\nWith the exception of bytes literals, these all correspond to\nimmutable data types, and hence the object's identity is less\nimportant than its value. Multiple evaluations of literals with the\nsame value (either the same occurrence in the program text or a\ndifferent occurrence) may obtain the same object or a different object\nwith the same value.\n", - 'attribute-access': '\nCustomizing attribute access\n****************************\n\nThe following methods can be defined to customize the meaning of\nattribute access (use of, assignment to, or deletion of ``x.name``)\nfor class instances.\n\nobject.__getattr__(self, name)\n\n Called when an attribute lookup has not found the attribute in the\n usual places (i.e. it is not an instance attribute nor is it found\n in the class tree for ``self``). ``name`` is the attribute name.\n This method should return the (computed) attribute value or raise\n an ``AttributeError`` exception.\n\n Note that if the attribute is found through the normal mechanism,\n ``__getattr__()`` is not called. (This is an intentional asymmetry\n between ``__getattr__()`` and ``__setattr__()``.) This is done both\n for efficiency reasons and because otherwise ``__getattr__()``\n would have no way to access other attributes of the instance. Note\n that at least for instance variables, you can fake total control by\n not inserting any values in the instance attribute dictionary (but\n instead inserting them in another object). See the\n ``__getattribute__()`` method below for a way to actually get total\n control over attribute access.\n\nobject.__getattribute__(self, name)\n\n Called unconditionally to implement attribute accesses for\n instances of the class. If the class also defines\n ``__getattr__()``, the latter will not be called unless\n ``__getattribute__()`` either calls it explicitly or raises an\n ``AttributeError``. This method should return the (computed)\n attribute value or raise an ``AttributeError`` exception. In order\n to avoid infinite recursion in this method, its implementation\n should always call the base class method with the same name to\n access any attributes it needs, for example,\n ``object.__getattribute__(self, name)``.\n\n Note: This method may still be bypassed when looking up special methods\n as the result of implicit invocation via language syntax or\n built-in functions. See *Special method lookup*.\n\nobject.__setattr__(self, name, value)\n\n Called when an attribute assignment is attempted. This is called\n instead of the normal mechanism (i.e. store the value in the\n instance dictionary). *name* is the attribute name, *value* is the\n value to be assigned to it.\n\n If ``__setattr__()`` wants to assign to an instance attribute, it\n should call the base class method with the same name, for example,\n ``object.__setattr__(self, name, value)``.\n\nobject.__delattr__(self, name)\n\n Like ``__setattr__()`` but for attribute deletion instead of\n assignment. This should only be implemented if ``del obj.name`` is\n meaningful for the object.\n\nobject.__dir__(self)\n\n Called when ``dir()`` is called on the object. A list must be\n returned.\n\n\nImplementing Descriptors\n========================\n\nThe following methods only apply when an instance of the class\ncontaining the method (a so-called *descriptor* class) appears in the\nclass dictionary of another class, known as the *owner* class. In the\nexamples below, "the attribute" refers to the attribute whose name is\nthe key of the property in the owner class\' ``__dict__``.\n\nobject.__get__(self, instance, owner)\n\n Called to get the attribute of the owner class (class attribute\n access) or of an instance of that class (instance attribute\n access). *owner* is always the owner class, while *instance* is the\n instance that the attribute was accessed through, or ``None`` when\n the attribute is accessed through the *owner*. This method should\n return the (computed) attribute value or raise an\n ``AttributeError`` exception.\n\nobject.__set__(self, instance, value)\n\n Called to set the attribute on an instance *instance* of the owner\n class to a new value, *value*.\n\nobject.__delete__(self, instance)\n\n Called to delete the attribute on an instance *instance* of the\n owner class.\n\n\nInvoking Descriptors\n====================\n\nIn general, a descriptor is an object attribute with "binding\nbehavior", one whose attribute access has been overridden by methods\nin the descriptor protocol: ``__get__()``, ``__set__()``, and\n``__delete__()``. If any of those methods are defined for an object,\nit is said to be a descriptor.\n\nThe default behavior for attribute access is to get, set, or delete\nthe attribute from an object\'s dictionary. For instance, ``a.x`` has a\nlookup chain starting with ``a.__dict__[\'x\']``, then\n``type(a).__dict__[\'x\']``, and continuing through the base classes of\n``type(a)`` excluding metaclasses.\n\nHowever, if the looked-up value is an object defining one of the\ndescriptor methods, then Python may override the default behavior and\ninvoke the descriptor method instead. Where this occurs in the\nprecedence chain depends on which descriptor methods were defined and\nhow they were called.\n\nThe starting point for descriptor invocation is a binding, ``a.x``.\nHow the arguments are assembled depends on ``a``:\n\nDirect Call\n The simplest and least common call is when user code directly\n invokes a descriptor method: ``x.__get__(a)``.\n\nInstance Binding\n If binding to an object instance, ``a.x`` is transformed into the\n call: ``type(a).__dict__[\'x\'].__get__(a, type(a))``.\n\nClass Binding\n If binding to a class, ``A.x`` is transformed into the call:\n ``A.__dict__[\'x\'].__get__(None, A)``.\n\nSuper Binding\n If ``a`` is an instance of ``super``, then the binding ``super(B,\n obj).m()`` searches ``obj.__class__.__mro__`` for the base class\n ``A`` immediately preceding ``B`` and then invokes the descriptor\n with the call: ``A.__dict__[\'m\'].__get__(obj, A)``.\n\nFor instance bindings, the precedence of descriptor invocation depends\non the which descriptor methods are defined. A descriptor can define\nany combination of ``__get__()``, ``__set__()`` and ``__delete__()``.\nIf it does not define ``__get__()``, then accessing the attribute will\nreturn the descriptor object itself unless there is a value in the\nobject\'s instance dictionary. If the descriptor defines ``__set__()``\nand/or ``__delete__()``, it is a data descriptor; if it defines\nneither, it is a non-data descriptor. Normally, data descriptors\ndefine both ``__get__()`` and ``__set__()``, while non-data\ndescriptors have just the ``__get__()`` method. Data descriptors with\n``__set__()`` and ``__get__()`` defined always override a redefinition\nin an instance dictionary. In contrast, non-data descriptors can be\noverridden by instances.\n\nPython methods (including ``staticmethod()`` and ``classmethod()``)\nare implemented as non-data descriptors. Accordingly, instances can\nredefine and override methods. This allows individual instances to\nacquire behaviors that differ from other instances of the same class.\n\nThe ``property()`` function is implemented as a data descriptor.\nAccordingly, instances cannot override the behavior of a property.\n\n\n__slots__\n=========\n\nBy default, instances of classes have a dictionary for attribute\nstorage. This wastes space for objects having very few instance\nvariables. The space consumption can become acute when creating large\nnumbers of instances.\n\nThe default can be overridden by defining *__slots__* in a class\ndefinition. The *__slots__* declaration takes a sequence of instance\nvariables and reserves just enough space in each instance to hold a\nvalue for each variable. Space is saved because *__dict__* is not\ncreated for each instance.\n\nobject.__slots__\n\n This class variable can be assigned a string, iterable, or sequence\n of strings with variable names used by instances. If defined in a\n class, *__slots__* reserves space for the declared variables and\n prevents the automatic creation of *__dict__* and *__weakref__* for\n each instance.\n\n\nNotes on using *__slots__*\n--------------------------\n\n* When inheriting from a class without *__slots__*, the *__dict__*\n attribute of that class will always be accessible, so a *__slots__*\n definition in the subclass is meaningless.\n\n* Without a *__dict__* variable, instances cannot be assigned new\n variables not listed in the *__slots__* definition. Attempts to\n assign to an unlisted variable name raises ``AttributeError``. If\n dynamic assignment of new variables is desired, then add\n ``\'__dict__\'`` to the sequence of strings in the *__slots__*\n declaration.\n\n* Without a *__weakref__* variable for each instance, classes defining\n *__slots__* do not support weak references to its instances. If weak\n reference support is needed, then add ``\'__weakref__\'`` to the\n sequence of strings in the *__slots__* declaration.\n\n* *__slots__* are implemented at the class level by creating\n descriptors (*Implementing Descriptors*) for each variable name. As\n a result, class attributes cannot be used to set default values for\n instance variables defined by *__slots__*; otherwise, the class\n attribute would overwrite the descriptor assignment.\n\n* The action of a *__slots__* declaration is limited to the class\n where it is defined. As a result, subclasses will have a *__dict__*\n unless they also define *__slots__* (which must only contain names\n of any *additional* slots).\n\n* If a class defines a slot also defined in a base class, the instance\n variable defined by the base class slot is inaccessible (except by\n retrieving its descriptor directly from the base class). This\n renders the meaning of the program undefined. In the future, a\n check may be added to prevent this.\n\n* Nonempty *__slots__* does not work for classes derived from\n "variable-length" built-in types such as ``int``, ``str`` and\n ``tuple``.\n\n* Any non-string iterable may be assigned to *__slots__*. Mappings may\n also be used; however, in the future, special meaning may be\n assigned to the values corresponding to each key.\n\n* *__class__* assignment works only if both classes have the same\n *__slots__*.\n', + 'attribute-access': '\nCustomizing attribute access\n****************************\n\nThe following methods can be defined to customize the meaning of\nattribute access (use of, assignment to, or deletion of ``x.name``)\nfor class instances.\n\nobject.__getattr__(self, name)\n\n Called when an attribute lookup has not found the attribute in the\n usual places (i.e. it is not an instance attribute nor is it found\n in the class tree for ``self``). ``name`` is the attribute name.\n This method should return the (computed) attribute value or raise\n an ``AttributeError`` exception.\n\n Note that if the attribute is found through the normal mechanism,\n ``__getattr__()`` is not called. (This is an intentional asymmetry\n between ``__getattr__()`` and ``__setattr__()``.) This is done both\n for efficiency reasons and because otherwise ``__getattr__()``\n would have no way to access other attributes of the instance. Note\n that at least for instance variables, you can fake total control by\n not inserting any values in the instance attribute dictionary (but\n instead inserting them in another object). See the\n ``__getattribute__()`` method below for a way to actually get total\n control over attribute access.\n\nobject.__getattribute__(self, name)\n\n Called unconditionally to implement attribute accesses for\n instances of the class. If the class also defines\n ``__getattr__()``, the latter will not be called unless\n ``__getattribute__()`` either calls it explicitly or raises an\n ``AttributeError``. This method should return the (computed)\n attribute value or raise an ``AttributeError`` exception. In order\n to avoid infinite recursion in this method, its implementation\n should always call the base class method with the same name to\n access any attributes it needs, for example,\n ``object.__getattribute__(self, name)``.\n\n Note: This method may still be bypassed when looking up special methods\n as the result of implicit invocation via language syntax or\n built-in functions. See *Special method lookup*.\n\nobject.__setattr__(self, name, value)\n\n Called when an attribute assignment is attempted. This is called\n instead of the normal mechanism (i.e. store the value in the\n instance dictionary). *name* is the attribute name, *value* is the\n value to be assigned to it.\n\n If ``__setattr__()`` wants to assign to an instance attribute, it\n should call the base class method with the same name, for example,\n ``object.__setattr__(self, name, value)``.\n\nobject.__delattr__(self, name)\n\n Like ``__setattr__()`` but for attribute deletion instead of\n assignment. This should only be implemented if ``del obj.name`` is\n meaningful for the object.\n\nobject.__dir__(self)\n\n Called when ``dir()`` is called on the object. A list must be\n returned.\n\n\nImplementing Descriptors\n========================\n\nThe following methods only apply when an instance of the class\ncontaining the method (a so-called *descriptor* class) appears in an\n*owner* class (the descriptor must be in either the owner\'s class\ndictionary or in the class dictionary for one of its parents). In the\nexamples below, "the attribute" refers to the attribute whose name is\nthe key of the property in the owner class\' ``__dict__``.\n\nobject.__get__(self, instance, owner)\n\n Called to get the attribute of the owner class (class attribute\n access) or of an instance of that class (instance attribute\n access). *owner* is always the owner class, while *instance* is the\n instance that the attribute was accessed through, or ``None`` when\n the attribute is accessed through the *owner*. This method should\n return the (computed) attribute value or raise an\n ``AttributeError`` exception.\n\nobject.__set__(self, instance, value)\n\n Called to set the attribute on an instance *instance* of the owner\n class to a new value, *value*.\n\nobject.__delete__(self, instance)\n\n Called to delete the attribute on an instance *instance* of the\n owner class.\n\n\nInvoking Descriptors\n====================\n\nIn general, a descriptor is an object attribute with "binding\nbehavior", one whose attribute access has been overridden by methods\nin the descriptor protocol: ``__get__()``, ``__set__()``, and\n``__delete__()``. If any of those methods are defined for an object,\nit is said to be a descriptor.\n\nThe default behavior for attribute access is to get, set, or delete\nthe attribute from an object\'s dictionary. For instance, ``a.x`` has a\nlookup chain starting with ``a.__dict__[\'x\']``, then\n``type(a).__dict__[\'x\']``, and continuing through the base classes of\n``type(a)`` excluding metaclasses.\n\nHowever, if the looked-up value is an object defining one of the\ndescriptor methods, then Python may override the default behavior and\ninvoke the descriptor method instead. Where this occurs in the\nprecedence chain depends on which descriptor methods were defined and\nhow they were called.\n\nThe starting point for descriptor invocation is a binding, ``a.x``.\nHow the arguments are assembled depends on ``a``:\n\nDirect Call\n The simplest and least common call is when user code directly\n invokes a descriptor method: ``x.__get__(a)``.\n\nInstance Binding\n If binding to an object instance, ``a.x`` is transformed into the\n call: ``type(a).__dict__[\'x\'].__get__(a, type(a))``.\n\nClass Binding\n If binding to a class, ``A.x`` is transformed into the call:\n ``A.__dict__[\'x\'].__get__(None, A)``.\n\nSuper Binding\n If ``a`` is an instance of ``super``, then the binding ``super(B,\n obj).m()`` searches ``obj.__class__.__mro__`` for the base class\n ``A`` immediately preceding ``B`` and then invokes the descriptor\n with the call: ``A.__dict__[\'m\'].__get__(obj, obj.__class__)``.\n\nFor instance bindings, the precedence of descriptor invocation depends\non the which descriptor methods are defined. A descriptor can define\nany combination of ``__get__()``, ``__set__()`` and ``__delete__()``.\nIf it does not define ``__get__()``, then accessing the attribute will\nreturn the descriptor object itself unless there is a value in the\nobject\'s instance dictionary. If the descriptor defines ``__set__()``\nand/or ``__delete__()``, it is a data descriptor; if it defines\nneither, it is a non-data descriptor. Normally, data descriptors\ndefine both ``__get__()`` and ``__set__()``, while non-data\ndescriptors have just the ``__get__()`` method. Data descriptors with\n``__set__()`` and ``__get__()`` defined always override a redefinition\nin an instance dictionary. In contrast, non-data descriptors can be\noverridden by instances.\n\nPython methods (including ``staticmethod()`` and ``classmethod()``)\nare implemented as non-data descriptors. Accordingly, instances can\nredefine and override methods. This allows individual instances to\nacquire behaviors that differ from other instances of the same class.\n\nThe ``property()`` function is implemented as a data descriptor.\nAccordingly, instances cannot override the behavior of a property.\n\n\n__slots__\n=========\n\nBy default, instances of classes have a dictionary for attribute\nstorage. This wastes space for objects having very few instance\nvariables. The space consumption can become acute when creating large\nnumbers of instances.\n\nThe default can be overridden by defining *__slots__* in a class\ndefinition. The *__slots__* declaration takes a sequence of instance\nvariables and reserves just enough space in each instance to hold a\nvalue for each variable. Space is saved because *__dict__* is not\ncreated for each instance.\n\nobject.__slots__\n\n This class variable can be assigned a string, iterable, or sequence\n of strings with variable names used by instances. If defined in a\n class, *__slots__* reserves space for the declared variables and\n prevents the automatic creation of *__dict__* and *__weakref__* for\n each instance.\n\n\nNotes on using *__slots__*\n--------------------------\n\n* When inheriting from a class without *__slots__*, the *__dict__*\n attribute of that class will always be accessible, so a *__slots__*\n definition in the subclass is meaningless.\n\n* Without a *__dict__* variable, instances cannot be assigned new\n variables not listed in the *__slots__* definition. Attempts to\n assign to an unlisted variable name raises ``AttributeError``. If\n dynamic assignment of new variables is desired, then add\n ``\'__dict__\'`` to the sequence of strings in the *__slots__*\n declaration.\n\n* Without a *__weakref__* variable for each instance, classes defining\n *__slots__* do not support weak references to its instances. If weak\n reference support is needed, then add ``\'__weakref__\'`` to the\n sequence of strings in the *__slots__* declaration.\n\n* *__slots__* are implemented at the class level by creating\n descriptors (*Implementing Descriptors*) for each variable name. As\n a result, class attributes cannot be used to set default values for\n instance variables defined by *__slots__*; otherwise, the class\n attribute would overwrite the descriptor assignment.\n\n* The action of a *__slots__* declaration is limited to the class\n where it is defined. As a result, subclasses will have a *__dict__*\n unless they also define *__slots__* (which must only contain names\n of any *additional* slots).\n\n* If a class defines a slot also defined in a base class, the instance\n variable defined by the base class slot is inaccessible (except by\n retrieving its descriptor directly from the base class). This\n renders the meaning of the program undefined. In the future, a\n check may be added to prevent this.\n\n* Nonempty *__slots__* does not work for classes derived from\n "variable-length" built-in types such as ``int``, ``str`` and\n ``tuple``.\n\n* Any non-string iterable may be assigned to *__slots__*. Mappings may\n also be used; however, in the future, special meaning may be\n assigned to the values corresponding to each key.\n\n* *__class__* assignment works only if both classes have the same\n *__slots__*.\n', 'attribute-references': '\nAttribute references\n********************\n\nAn attribute reference is a primary followed by a period and a name:\n\n attributeref ::= primary "." identifier\n\nThe primary must evaluate to an object of a type that supports\nattribute references, which most objects do. This object is then\nasked to produce the attribute whose name is the identifier (which can\nbe customized by overriding the ``__getattr__()`` method). If this\nattribute is not available, the exception ``AttributeError`` is\nraised. Otherwise, the type and value of the object produced is\ndetermined by the object. Multiple evaluations of the same attribute\nreference may yield different objects.\n', 'augassign': '\nAugmented assignment statements\n*******************************\n\nAugmented assignment is the combination, in a single statement, of a\nbinary operation and an assignment statement:\n\n augmented_assignment_stmt ::= augtarget augop (expression_list | yield_expression)\n augtarget ::= identifier | attributeref | subscription | slicing\n augop ::= "+=" | "-=" | "*=" | "/=" | "//=" | "%=" | "**="\n | ">>=" | "<<=" | "&=" | "^=" | "|="\n\n(See section *Primaries* for the syntax definitions for the last three\nsymbols.)\n\nAn augmented assignment evaluates the target (which, unlike normal\nassignment statements, cannot be an unpacking) and the expression\nlist, performs the binary operation specific to the type of assignment\non the two operands, and assigns the result to the original target.\nThe target is only evaluated once.\n\nAn augmented assignment expression like ``x += 1`` can be rewritten as\n``x = x + 1`` to achieve a similar, but not exactly equal effect. In\nthe augmented version, ``x`` is only evaluated once. Also, when\npossible, the actual operation is performed *in-place*, meaning that\nrather than creating a new object and assigning that to the target,\nthe old object is modified instead.\n\nWith the exception of assigning to tuples and multiple targets in a\nsingle statement, the assignment done by augmented assignment\nstatements is handled the same way as normal assignments. Similarly,\nwith the exception of the possible *in-place* behavior, the binary\noperation performed by augmented assignment is the same as the normal\nbinary operations.\n\nFor targets which are attribute references, the same *caveat about\nclass and instance attributes* applies as for regular assignments.\n', 'binary': '\nBinary arithmetic operations\n****************************\n\nThe binary arithmetic operations have the conventional priority\nlevels. Note that some of these operations also apply to certain non-\nnumeric types. Apart from the power operator, there are only two\nlevels, one for multiplicative operators and one for additive\noperators:\n\n m_expr ::= u_expr | m_expr "*" u_expr | m_expr "//" u_expr | m_expr "/" u_expr\n | m_expr "%" u_expr\n a_expr ::= m_expr | a_expr "+" m_expr | a_expr "-" m_expr\n\nThe ``*`` (multiplication) operator yields the product of its\narguments. The arguments must either both be numbers, or one argument\nmust be an integer and the other must be a sequence. In the former\ncase, the numbers are converted to a common type and then multiplied\ntogether. In the latter case, sequence repetition is performed; a\nnegative repetition factor yields an empty sequence.\n\nThe ``/`` (division) and ``//`` (floor division) operators yield the\nquotient of their arguments. The numeric arguments are first\nconverted to a common type. Integer division yields a float, while\nfloor division of integers results in an integer; the result is that\nof mathematical division with the \'floor\' function applied to the\nresult. Division by zero raises the ``ZeroDivisionError`` exception.\n\nThe ``%`` (modulo) operator yields the remainder from the division of\nthe first argument by the second. The numeric arguments are first\nconverted to a common type. A zero right argument raises the\n``ZeroDivisionError`` exception. The arguments may be floating point\nnumbers, e.g., ``3.14%0.7`` equals ``0.34`` (since ``3.14`` equals\n``4*0.7 + 0.34``.) The modulo operator always yields a result with\nthe same sign as its second operand (or zero); the absolute value of\nthe result is strictly smaller than the absolute value of the second\noperand [1].\n\nThe floor division and modulo operators are connected by the following\nidentity: ``x == (x//y)*y + (x%y)``. Floor division and modulo are\nalso connected with the built-in function ``divmod()``: ``divmod(x, y)\n== (x//y, x%y)``. [2].\n\nIn addition to performing the modulo operation on numbers, the ``%``\noperator is also overloaded by string objects to perform old-style\nstring formatting (also known as interpolation). The syntax for\nstring formatting is described in the Python Library Reference,\nsection *Old String Formatting Operations*.\n\nThe floor division operator, the modulo operator, and the ``divmod()``\nfunction are not defined for complex numbers. Instead, convert to a\nfloating point number using the ``abs()`` function if appropriate.\n\nThe ``+`` (addition) operator yields the sum of its arguments. The\narguments must either both be numbers or both sequences of the same\ntype. In the former case, the numbers are converted to a common type\nand then added together. In the latter case, the sequences are\nconcatenated.\n\nThe ``-`` (subtraction) operator yields the difference of its\narguments. The numeric arguments are first converted to a common\ntype.\n', @@ -16,9 +16,9 @@ 'break': '\nThe ``break`` statement\n***********************\n\n break_stmt ::= "break"\n\n``break`` may only occur syntactically nested in a ``for`` or\n``while`` loop, but not nested in a function or class definition\nwithin that loop.\n\nIt terminates the nearest enclosing loop, skipping the optional\n``else`` clause if the loop has one.\n\nIf a ``for`` loop is terminated by ``break``, the loop control target\nkeeps its current value.\n\nWhen ``break`` passes control out of a ``try`` statement with a\n``finally`` clause, that ``finally`` clause is executed before really\nleaving the loop.\n', 'callable-types': '\nEmulating callable objects\n**************************\n\nobject.__call__(self[, args...])\n\n Called when the instance is "called" as a function; if this method\n is defined, ``x(arg1, arg2, ...)`` is a shorthand for\n ``x.__call__(arg1, arg2, ...)``.\n', 'calls': '\nCalls\n*****\n\nA call calls a callable object (e.g., a function) with a possibly\nempty series of arguments:\n\n call ::= primary "(" [argument_list [","] | comprehension] ")"\n argument_list ::= positional_arguments ["," keyword_arguments]\n ["," "*" expression] ["," keyword_arguments]\n ["," "**" expression]\n | keyword_arguments ["," "*" expression]\n ["," keyword_arguments] ["," "**" expression]\n | "*" expression ["," keyword_arguments] ["," "**" expression]\n | "**" expression\n positional_arguments ::= expression ("," expression)*\n keyword_arguments ::= keyword_item ("," keyword_item)*\n keyword_item ::= identifier "=" expression\n\nA trailing comma may be present after the positional and keyword\narguments but does not affect the semantics.\n\nThe primary must evaluate to a callable object (user-defined\nfunctions, built-in functions, methods of built-in objects, class\nobjects, methods of class instances, and all objects having a\n``__call__()`` method are callable). All argument expressions are\nevaluated before the call is attempted. Please refer to section\n*Function definitions* for the syntax of formal parameter lists.\n\nIf keyword arguments are present, they are first converted to\npositional arguments, as follows. First, a list of unfilled slots is\ncreated for the formal parameters. If there are N positional\narguments, they are placed in the first N slots. Next, for each\nkeyword argument, the identifier is used to determine the\ncorresponding slot (if the identifier is the same as the first formal\nparameter name, the first slot is used, and so on). If the slot is\nalready filled, a ``TypeError`` exception is raised. Otherwise, the\nvalue of the argument is placed in the slot, filling it (even if the\nexpression is ``None``, it fills the slot). When all arguments have\nbeen processed, the slots that are still unfilled are filled with the\ncorresponding default value from the function definition. (Default\nvalues are calculated, once, when the function is defined; thus, a\nmutable object such as a list or dictionary used as default value will\nbe shared by all calls that don\'t specify an argument value for the\ncorresponding slot; this should usually be avoided.) If there are any\nunfilled slots for which no default value is specified, a\n``TypeError`` exception is raised. Otherwise, the list of filled\nslots is used as the argument list for the call.\n\n**CPython implementation detail:** An implementation may provide\nbuilt-in functions whose positional parameters do not have names, even\nif they are \'named\' for the purpose of documentation, and which\ntherefore cannot be supplied by keyword. In CPython, this is the case\nfor functions implemented in C that use ``PyArg_ParseTuple()`` to\nparse their arguments.\n\nIf there are more positional arguments than there are formal parameter\nslots, a ``TypeError`` exception is raised, unless a formal parameter\nusing the syntax ``*identifier`` is present; in this case, that formal\nparameter receives a tuple containing the excess positional arguments\n(or an empty tuple if there were no excess positional arguments).\n\nIf any keyword argument does not correspond to a formal parameter\nname, a ``TypeError`` exception is raised, unless a formal parameter\nusing the syntax ``**identifier`` is present; in this case, that\nformal parameter receives a dictionary containing the excess keyword\narguments (using the keywords as keys and the argument values as\ncorresponding values), or a (new) empty dictionary if there were no\nexcess keyword arguments.\n\nIf the syntax ``*expression`` appears in the function call,\n``expression`` must evaluate to a sequence. Elements from this\nsequence are treated as if they were additional positional arguments;\nif there are positional arguments *x1*,..., *xN*, and ``expression``\nevaluates to a sequence *y1*, ..., *yM*, this is equivalent to a call\nwith M+N positional arguments *x1*, ..., *xN*, *y1*, ..., *yM*.\n\nA consequence of this is that although the ``*expression`` syntax may\nappear *after* some keyword arguments, it is processed *before* the\nkeyword arguments (and the ``**expression`` argument, if any -- see\nbelow). So:\n\n >>> def f(a, b):\n ... print(a, b)\n ...\n >>> f(b=1, *(2,))\n 2 1\n >>> f(a=1, *(2,))\n Traceback (most recent call last):\n File "", line 1, in ?\n TypeError: f() got multiple values for keyword argument \'a\'\n >>> f(1, *(2,))\n 1 2\n\nIt is unusual for both keyword arguments and the ``*expression``\nsyntax to be used in the same call, so in practice this confusion does\nnot arise.\n\nIf the syntax ``**expression`` appears in the function call,\n``expression`` must evaluate to a mapping, the contents of which are\ntreated as additional keyword arguments. In the case of a keyword\nappearing in both ``expression`` and as an explicit keyword argument,\na ``TypeError`` exception is raised.\n\nFormal parameters using the syntax ``*identifier`` or ``**identifier``\ncannot be used as positional argument slots or as keyword argument\nnames.\n\nA call always returns some value, possibly ``None``, unless it raises\nan exception. How this value is computed depends on the type of the\ncallable object.\n\nIf it is---\n\na user-defined function:\n The code block for the function is executed, passing it the\n argument list. The first thing the code block will do is bind the\n formal parameters to the arguments; this is described in section\n *Function definitions*. When the code block executes a ``return``\n statement, this specifies the return value of the function call.\n\na built-in function or method:\n The result is up to the interpreter; see *Built-in Functions* for\n the descriptions of built-in functions and methods.\n\na class object:\n A new instance of that class is returned.\n\na class instance method:\n The corresponding user-defined function is called, with an argument\n list that is one longer than the argument list of the call: the\n instance becomes the first argument.\n\na class instance:\n The class must define a ``__call__()`` method; the effect is then\n the same as if that method was called.\n', - 'class': '\nClass definitions\n*****************\n\nA class definition defines a class object (see section *The standard\ntype hierarchy*):\n\n classdef ::= [decorators] "class" classname [inheritance] ":" suite\n inheritance ::= "(" [argument_list [","] | comprehension] ")"\n classname ::= identifier\n\nA class definition is an executable statement. The inheritance list\nusually gives a list of base classes (see *Customizing class creation*\nfor more advanced uses), so each item in the list should evaluate to a\nclass object which allows subclassing. Classes without an inheritance\nlist inherit, by default, from the base class ``object``; hence,\n\n class Foo:\n pass\n\nis equivalent to\n\n class Foo(object):\n pass\n\nThe class\'s suite is then executed in a new execution frame (see\n*Naming and binding*), using a newly created local namespace and the\noriginal global namespace. (Usually, the suite contains mostly\nfunction definitions.) When the class\'s suite finishes execution, its\nexecution frame is discarded but its local namespace is saved. [4] A\nclass object is then created using the inheritance list for the base\nclasses and the saved local namespace for the attribute dictionary.\nThe class name is bound to this class object in the original local\nnamespace.\n\nClass creation can be customized heavily using *metaclasses*.\n\nClasses can also be decorated: just like when decorating functions,\n\n @f1(arg)\n @f2\n class Foo: pass\n\nis equivalent to\n\n class Foo: pass\n Foo = f1(arg)(f2(Foo))\n\nThe evaluation rules for the decorator expressions are the same as for\nfunction decorators. The result must be a class object, which is then\nbound to the class name.\n\n**Programmer\'s note:** Variables defined in the class definition are\nclass attributes; they are shared by instances. Instance attributes\ncan be set in a method with ``self.name = value``. Both class and\ninstance attributes are accessible through the notation\n"``self.name``", and an instance attribute hides a class attribute\nwith the same name when accessed in this way. Class attributes can be\nused as defaults for instance attributes, but using mutable values\nthere can lead to unexpected results. *Descriptors* can be used to\ncreate instance variables with different implementation details.\n\nSee also:\n\n **PEP 3116** - Metaclasses in Python 3 **PEP 3129** - Class\n Decorators\n\n-[ Footnotes ]-\n\n[1] The exception is propagated to the invocation stack only if there\n is no ``finally`` clause that negates the exception.\n\n[2] Currently, control "flows off the end" except in the case of an\n exception or the execution of a ``return``, ``continue``, or\n ``break`` statement.\n\n[3] A string literal appearing as the first statement in the function\n body is transformed into the function\'s ``__doc__`` attribute and\n therefore the function\'s *docstring*.\n\n[4] A string literal appearing as the first statement in the class\n body is transformed into the namespace\'s ``__doc__`` item and\n therefore the class\'s *docstring*.\n', + 'class': '\nClass definitions\n*****************\n\nA class definition defines a class object (see section *The standard\ntype hierarchy*):\n\n classdef ::= [decorators] "class" classname [inheritance] ":" suite\n inheritance ::= "(" [argument_list [","] | comprehension] ")"\n classname ::= identifier\n\nA class definition is an executable statement. The inheritance list\nusually gives a list of base classes (see *Customizing class creation*\nfor more advanced uses), so each item in the list should evaluate to a\nclass object which allows subclassing. Classes without an inheritance\nlist inherit, by default, from the base class ``object``; hence,\n\n class Foo:\n pass\n\nis equivalent to\n\n class Foo(object):\n pass\n\nThe class\'s suite is then executed in a new execution frame (see\n*Naming and binding*), using a newly created local namespace and the\noriginal global namespace. (Usually, the suite contains mostly\nfunction definitions.) When the class\'s suite finishes execution, its\nexecution frame is discarded but its local namespace is saved. [4] A\nclass object is then created using the inheritance list for the base\nclasses and the saved local namespace for the attribute dictionary.\nThe class name is bound to this class object in the original local\nnamespace.\n\nClass creation can be customized heavily using *metaclasses*.\n\nClasses can also be decorated: just like when decorating functions,\n\n @f1(arg)\n @f2\n class Foo: pass\n\nis equivalent to\n\n class Foo: pass\n Foo = f1(arg)(f2(Foo))\n\nThe evaluation rules for the decorator expressions are the same as for\nfunction decorators. The result must be a class object, which is then\nbound to the class name.\n\n**Programmer\'s note:** Variables defined in the class definition are\nclass attributes; they are shared by instances. Instance attributes\ncan be set in a method with ``self.name = value``. Both class and\ninstance attributes are accessible through the notation\n"``self.name``", and an instance attribute hides a class attribute\nwith the same name when accessed in this way. Class attributes can be\nused as defaults for instance attributes, but using mutable values\nthere can lead to unexpected results. *Descriptors* can be used to\ncreate instance variables with different implementation details.\n\nSee also:\n\n **PEP 3115** - Metaclasses in Python 3 **PEP 3129** - Class\n Decorators\n\n-[ Footnotes ]-\n\n[1] The exception is propagated to the invocation stack only if there\n is no ``finally`` clause that negates the exception.\n\n[2] Currently, control "flows off the end" except in the case of an\n exception or the execution of a ``return``, ``continue``, or\n ``break`` statement.\n\n[3] A string literal appearing as the first statement in the function\n body is transformed into the function\'s ``__doc__`` attribute and\n therefore the function\'s *docstring*.\n\n[4] A string literal appearing as the first statement in the class\n body is transformed into the namespace\'s ``__doc__`` item and\n therefore the class\'s *docstring*.\n', 'comparisons': '\nComparisons\n***********\n\nUnlike C, all comparison operations in Python have the same priority,\nwhich is lower than that of any arithmetic, shifting or bitwise\noperation. Also unlike C, expressions like ``a < b < c`` have the\ninterpretation that is conventional in mathematics:\n\n comparison ::= or_expr ( comp_operator or_expr )*\n comp_operator ::= "<" | ">" | "==" | ">=" | "<=" | "!="\n | "is" ["not"] | ["not"] "in"\n\nComparisons yield boolean values: ``True`` or ``False``.\n\nComparisons can be chained arbitrarily, e.g., ``x < y <= z`` is\nequivalent to ``x < y and y <= z``, except that ``y`` is evaluated\nonly once (but in both cases ``z`` is not evaluated at all when ``x <\ny`` is found to be false).\n\nFormally, if *a*, *b*, *c*, ..., *y*, *z* are expressions and *op1*,\n*op2*, ..., *opN* are comparison operators, then ``a op1 b op2 c ... y\nopN z`` is equivalent to ``a op1 b and b op2 c and ... y opN z``,\nexcept that each expression is evaluated at most once.\n\nNote that ``a op1 b op2 c`` doesn\'t imply any kind of comparison\nbetween *a* and *c*, so that, e.g., ``x < y > z`` is perfectly legal\n(though perhaps not pretty).\n\nThe operators ``<``, ``>``, ``==``, ``>=``, ``<=``, and ``!=`` compare\nthe values of two objects. The objects need not have the same type.\nIf both are numbers, they are converted to a common type. Otherwise,\nthe ``==`` and ``!=`` operators *always* consider objects of different\ntypes to be unequal, while the ``<``, ``>``, ``>=`` and ``<=``\noperators raise a ``TypeError`` when comparing objects of different\ntypes that do not implement these operators for the given pair of\ntypes. You can control comparison behavior of objects of non-built-in\ntypes by defining rich comparison methods like ``__gt__()``, described\nin section *Basic customization*.\n\nComparison of objects of the same type depends on the type:\n\n* Numbers are compared arithmetically.\n\n* The values ``float(\'NaN\')`` and ``Decimal(\'NaN\')`` are special. The\n are identical to themselves, ``x is x`` but are not equal to\n themselves, ``x != x``. Additionally, comparing any value to a\n not-a-number value will return ``False``. For example, both ``3 <\n float(\'NaN\')`` and ``float(\'NaN\') < 3`` will return ``False``.\n\n* Bytes objects are compared lexicographically using the numeric\n values of their elements.\n\n* Strings are compared lexicographically using the numeric equivalents\n (the result of the built-in function ``ord()``) of their characters.\n [3] String and bytes object can\'t be compared!\n\n* Tuples and lists are compared lexicographically using comparison of\n corresponding elements. This means that to compare equal, each\n element must compare equal and the two sequences must be of the same\n type and have the same length.\n\n If not equal, the sequences are ordered the same as their first\n differing elements. For example, ``[1,2,x] <= [1,2,y]`` has the\n same value as ``x <= y``. If the corresponding element does not\n exist, the shorter sequence is ordered first (for example, ``[1,2] <\n [1,2,3]``).\n\n* Mappings (dictionaries) compare equal if and only if they have the\n same ``(key, value)`` pairs. Order comparisons ``(\'<\', \'<=\', \'>=\',\n \'>\')`` raise ``TypeError``.\n\n* Sets and frozensets define comparison operators to mean subset and\n superset tests. Those relations do not define total orderings (the\n two sets ``{1,2}`` and {2,3} are not equal, nor subsets of one\n another, nor supersets of one another). Accordingly, sets are not\n appropriate arguments for functions which depend on total ordering.\n For example, ``min()``, ``max()``, and ``sorted()`` produce\n undefined results given a list of sets as inputs.\n\n* Most other objects of built-in types compare unequal unless they are\n the same object; the choice whether one object is considered smaller\n or larger than another one is made arbitrarily but consistently\n within one execution of a program.\n\nComparison of objects of the differing types depends on whether either\nof the types provide explicit support for the comparison. Most\nnumeric types can be compared with one another, but comparisons of\n``float`` and ``Decimal`` are not supported to avoid the inevitable\nconfusion arising from representation issues such as ``float(\'1.1\')``\nbeing inexactly represented and therefore not exactly equal to\n``Decimal(\'1.1\')`` which is. When cross-type comparison is not\nsupported, the comparison method returns ``NotImplemented``. This can\ncreate the illusion of non-transitivity between supported cross-type\ncomparisons and unsupported comparisons. For example, ``Decimal(2) ==\n2`` and ``2 == float(2)`` but ``Decimal(2) != float(2)``.\n\nThe operators ``in`` and ``not in`` test for membership. ``x in s``\nevaluates to true if *x* is a member of *s*, and false otherwise. ``x\nnot in s`` returns the negation of ``x in s``. All built-in sequences\nand set types support this as well as dictionary, for which ``in``\ntests whether a the dictionary has a given key. For container types\nsuch as list, tuple, set, frozenset, dict, or collections.deque, the\nexpression ``x in y`` is equivalent to ``any(x is e or x == e for e in\ny)``.\n\nFor the string and bytes types, ``x in y`` is true if and only if *x*\nis a substring of *y*. An equivalent test is ``y.find(x) != -1``.\nEmpty strings are always considered to be a substring of any other\nstring, so ``"" in "abc"`` will return ``True``.\n\nFor user-defined classes which define the ``__contains__()`` method,\n``x in y`` is true if and only if ``y.__contains__(x)`` is true.\n\nFor user-defined classes which do not define ``__contains__()`` but do\ndefine ``__iter__()``, ``x in y`` is true if some value ``z`` with ``x\n== z`` is produced while iterating over ``y``. If an exception is\nraised during the iteration, it is as if ``in`` raised that exception.\n\nLastly, the old-style iteration protocol is tried: if a class defines\n``__getitem__()``, ``x in y`` is true if and only if there is a non-\nnegative integer index *i* such that ``x == y[i]``, and all lower\ninteger indices do not raise ``IndexError`` exception. (If any other\nexception is raised, it is as if ``in`` raised that exception).\n\nThe operator ``not in`` is defined to have the inverse true value of\n``in``.\n\nThe operators ``is`` and ``is not`` test for object identity: ``x is\ny`` is true if and only if *x* and *y* are the same object. ``x is\nnot y`` yields the inverse truth value. [4]\n', - 'compound': '\nCompound statements\n*******************\n\nCompound statements contain (groups of) other statements; they affect\nor control the execution of those other statements in some way. In\ngeneral, compound statements span multiple lines, although in simple\nincarnations a whole compound statement may be contained in one line.\n\nThe ``if``, ``while`` and ``for`` statements implement traditional\ncontrol flow constructs. ``try`` specifies exception handlers and/or\ncleanup code for a group of statements, while the ``with`` statement\nallows the execution of initialization and finalization code around a\nblock of code. Function and class definitions are also syntactically\ncompound statements.\n\nCompound statements consist of one or more \'clauses.\' A clause\nconsists of a header and a \'suite.\' The clause headers of a\nparticular compound statement are all at the same indentation level.\nEach clause header begins with a uniquely identifying keyword and ends\nwith a colon. A suite is a group of statements controlled by a\nclause. A suite can be one or more semicolon-separated simple\nstatements on the same line as the header, following the header\'s\ncolon, or it can be one or more indented statements on subsequent\nlines. Only the latter form of suite can contain nested compound\nstatements; the following is illegal, mostly because it wouldn\'t be\nclear to which ``if`` clause a following ``else`` clause would belong:\n\n if test1: if test2: print(x)\n\nAlso note that the semicolon binds tighter than the colon in this\ncontext, so that in the following example, either all or none of the\n``print()`` calls are executed:\n\n if x < y < z: print(x); print(y); print(z)\n\nSummarizing:\n\n compound_stmt ::= if_stmt\n | while_stmt\n | for_stmt\n | try_stmt\n | with_stmt\n | funcdef\n | classdef\n suite ::= stmt_list NEWLINE | NEWLINE INDENT statement+ DEDENT\n statement ::= stmt_list NEWLINE | compound_stmt\n stmt_list ::= simple_stmt (";" simple_stmt)* [";"]\n\nNote that statements always end in a ``NEWLINE`` possibly followed by\na ``DEDENT``. Also note that optional continuation clauses always\nbegin with a keyword that cannot start a statement, thus there are no\nambiguities (the \'dangling ``else``\' problem is solved in Python by\nrequiring nested ``if`` statements to be indented).\n\nThe formatting of the grammar rules in the following sections places\neach clause on a separate line for clarity.\n\n\nThe ``if`` statement\n====================\n\nThe ``if`` statement is used for conditional execution:\n\n if_stmt ::= "if" expression ":" suite\n ( "elif" expression ":" suite )*\n ["else" ":" suite]\n\nIt selects exactly one of the suites by evaluating the expressions one\nby one until one is found to be true (see section *Boolean operations*\nfor the definition of true and false); then that suite is executed\n(and no other part of the ``if`` statement is executed or evaluated).\nIf all expressions are false, the suite of the ``else`` clause, if\npresent, is executed.\n\n\nThe ``while`` statement\n=======================\n\nThe ``while`` statement is used for repeated execution as long as an\nexpression is true:\n\n while_stmt ::= "while" expression ":" suite\n ["else" ":" suite]\n\nThis repeatedly tests the expression and, if it is true, executes the\nfirst suite; if the expression is false (which may be the first time\nit is tested) the suite of the ``else`` clause, if present, is\nexecuted and the loop terminates.\n\nA ``break`` statement executed in the first suite terminates the loop\nwithout executing the ``else`` clause\'s suite. A ``continue``\nstatement executed in the first suite skips the rest of the suite and\ngoes back to testing the expression.\n\n\nThe ``for`` statement\n=====================\n\nThe ``for`` statement is used to iterate over the elements of a\nsequence (such as a string, tuple or list) or other iterable object:\n\n for_stmt ::= "for" target_list "in" expression_list ":" suite\n ["else" ":" suite]\n\nThe expression list is evaluated once; it should yield an iterable\nobject. An iterator is created for the result of the\n``expression_list``. The suite is then executed once for each item\nprovided by the iterator, in the order of ascending indices. Each\nitem in turn is assigned to the target list using the standard rules\nfor assignments (see *Assignment statements*), and then the suite is\nexecuted. When the items are exhausted (which is immediately when the\nsequence is empty or an iterator raises a ``StopIteration``\nexception), the suite in the ``else`` clause, if present, is executed,\nand the loop terminates.\n\nA ``break`` statement executed in the first suite terminates the loop\nwithout executing the ``else`` clause\'s suite. A ``continue``\nstatement executed in the first suite skips the rest of the suite and\ncontinues with the next item, or with the ``else`` clause if there was\nno next item.\n\nThe suite may assign to the variable(s) in the target list; this does\nnot affect the next item assigned to it.\n\nNames in the target list are not deleted when the loop is finished,\nbut if the sequence is empty, it will not have been assigned to at all\nby the loop. Hint: the built-in function ``range()`` returns an\niterator of integers suitable to emulate the effect of Pascal\'s ``for\ni := a to b do``; e.g., ``list(range(3))`` returns the list ``[0, 1,\n2]``.\n\nNote: There is a subtlety when the sequence is being modified by the loop\n (this can only occur for mutable sequences, i.e. lists). An\n internal counter is used to keep track of which item is used next,\n and this is incremented on each iteration. When this counter has\n reached the length of the sequence the loop terminates. This means\n that if the suite deletes the current (or a previous) item from the\n sequence, the next item will be skipped (since it gets the index of\n the current item which has already been treated). Likewise, if the\n suite inserts an item in the sequence before the current item, the\n current item will be treated again the next time through the loop.\n This can lead to nasty bugs that can be avoided by making a\n temporary copy using a slice of the whole sequence, e.g.,\n\n for x in a[:]:\n if x < 0: a.remove(x)\n\n\nThe ``try`` statement\n=====================\n\nThe ``try`` statement specifies exception handlers and/or cleanup code\nfor a group of statements:\n\n try_stmt ::= try1_stmt | try2_stmt\n try1_stmt ::= "try" ":" suite\n ("except" [expression ["as" target]] ":" suite)+\n ["else" ":" suite]\n ["finally" ":" suite]\n try2_stmt ::= "try" ":" suite\n "finally" ":" suite\n\nThe ``except`` clause(s) specify one or more exception handlers. When\nno exception occurs in the ``try`` clause, no exception handler is\nexecuted. When an exception occurs in the ``try`` suite, a search for\nan exception handler is started. This search inspects the except\nclauses in turn until one is found that matches the exception. An\nexpression-less except clause, if present, must be last; it matches\nany exception. For an except clause with an expression, that\nexpression is evaluated, and the clause matches the exception if the\nresulting object is "compatible" with the exception. An object is\ncompatible with an exception if it is the class or a base class of the\nexception object or a tuple containing an item compatible with the\nexception.\n\nIf no except clause matches the exception, the search for an exception\nhandler continues in the surrounding code and on the invocation stack.\n[1]\n\nIf the evaluation of an expression in the header of an except clause\nraises an exception, the original search for a handler is canceled and\na search starts for the new exception in the surrounding code and on\nthe call stack (it is treated as if the entire ``try`` statement\nraised the exception).\n\nWhen a matching except clause is found, the exception is assigned to\nthe target specified after the ``as`` keyword in that except clause,\nif present, and the except clause\'s suite is executed. All except\nclauses must have an executable block. When the end of this block is\nreached, execution continues normally after the entire try statement.\n(This means that if two nested handlers exist for the same exception,\nand the exception occurs in the try clause of the inner handler, the\nouter handler will not handle the exception.)\n\nWhen an exception has been assigned using ``as target``, it is cleared\nat the end of the except clause. This is as if\n\n except E as N:\n foo\n\nwas translated to\n\n except E as N:\n try:\n foo\n finally:\n del N\n\nThis means the exception must be assigned to a different name to be\nable to refer to it after the except clause. Exceptions are cleared\nbecause with the traceback attached to them, they form a reference\ncycle with the stack frame, keeping all locals in that frame alive\nuntil the next garbage collection occurs.\n\nBefore an except clause\'s suite is executed, details about the\nexception are stored in the ``sys`` module and can be access via\n``sys.exc_info()``. ``sys.exc_info()`` returns a 3-tuple consisting of\nthe exception class, the exception instance and a traceback object\n(see section *The standard type hierarchy*) identifying the point in\nthe program where the exception occurred. ``sys.exc_info()`` values\nare restored to their previous values (before the call) when returning\nfrom a function that handled an exception.\n\nThe optional ``else`` clause is executed if and when control flows off\nthe end of the ``try`` clause. [2] Exceptions in the ``else`` clause\nare not handled by the preceding ``except`` clauses.\n\nIf ``finally`` is present, it specifies a \'cleanup\' handler. The\n``try`` clause is executed, including any ``except`` and ``else``\nclauses. If an exception occurs in any of the clauses and is not\nhandled, the exception is temporarily saved. The ``finally`` clause is\nexecuted. If there is a saved exception, it is re-raised at the end\nof the ``finally`` clause. If the ``finally`` clause raises another\nexception or executes a ``return`` or ``break`` statement, the saved\nexception is lost. The exception information is not available to the\nprogram during execution of the ``finally`` clause.\n\nWhen a ``return``, ``break`` or ``continue`` statement is executed in\nthe ``try`` suite of a ``try``...``finally`` statement, the\n``finally`` clause is also executed \'on the way out.\' A ``continue``\nstatement is illegal in the ``finally`` clause. (The reason is a\nproblem with the current implementation --- this restriction may be\nlifted in the future).\n\nAdditional information on exceptions can be found in section\n*Exceptions*, and information on using the ``raise`` statement to\ngenerate exceptions may be found in section *The raise statement*.\n\n\nThe ``with`` statement\n======================\n\nThe ``with`` statement is used to wrap the execution of a block with\nmethods defined by a context manager (see section *With Statement\nContext Managers*). This allows common\n``try``...``except``...``finally`` usage patterns to be encapsulated\nfor convenient reuse.\n\n with_stmt ::= "with" with_item ("," with_item)* ":" suite\n with_item ::= expression ["as" target]\n\nThe execution of the ``with`` statement with one "item" proceeds as\nfollows:\n\n1. The context expression (the expression given in the ``with_item``)\n is evaluated to obtain a context manager.\n\n2. The context manager\'s ``__exit__()`` is loaded for later use.\n\n3. The context manager\'s ``__enter__()`` method is invoked.\n\n4. If a target was included in the ``with`` statement, the return\n value from ``__enter__()`` is assigned to it.\n\n Note: The ``with`` statement guarantees that if the ``__enter__()``\n method returns without an error, then ``__exit__()`` will always\n be called. Thus, if an error occurs during the assignment to the\n target list, it will be treated the same as an error occurring\n within the suite would be. See step 6 below.\n\n5. The suite is executed.\n\n6. The context manager\'s ``__exit__()`` method is invoked. If an\n exception caused the suite to be exited, its type, value, and\n traceback are passed as arguments to ``__exit__()``. Otherwise,\n three ``None`` arguments are supplied.\n\n If the suite was exited due to an exception, and the return value\n from the ``__exit__()`` method was false, the exception is\n reraised. If the return value was true, the exception is\n suppressed, and execution continues with the statement following\n the ``with`` statement.\n\n If the suite was exited for any reason other than an exception, the\n return value from ``__exit__()`` is ignored, and execution proceeds\n at the normal location for the kind of exit that was taken.\n\nWith more than one item, the context managers are processed as if\nmultiple ``with`` statements were nested:\n\n with A() as a, B() as b:\n suite\n\nis equivalent to\n\n with A() as a:\n with B() as b:\n suite\n\nChanged in version 3.1: Support for multiple context expressions.\n\nSee also:\n\n **PEP 0343** - The "with" statement\n The specification, background, and examples for the Python\n ``with`` statement.\n\n\nFunction definitions\n====================\n\nA function definition defines a user-defined function object (see\nsection *The standard type hierarchy*):\n\n funcdef ::= [decorators] "def" funcname "(" [parameter_list] ")" ["->" expression] ":" suite\n decorators ::= decorator+\n decorator ::= "@" dotted_name ["(" [argument_list [","]] ")"] NEWLINE\n dotted_name ::= identifier ("." identifier)*\n parameter_list ::= (defparameter ",")*\n ( "*" [parameter] ("," defparameter)*\n [, "**" parameter]\n | "**" parameter\n | defparameter [","] )\n parameter ::= identifier [":" expression]\n defparameter ::= parameter ["=" expression]\n funcname ::= identifier\n\nA function definition is an executable statement. Its execution binds\nthe function name in the current local namespace to a function object\n(a wrapper around the executable code for the function). This\nfunction object contains a reference to the current global namespace\nas the global namespace to be used when the function is called.\n\nThe function definition does not execute the function body; this gets\nexecuted only when the function is called. [3]\n\nA function definition may be wrapped by one or more *decorator*\nexpressions. Decorator expressions are evaluated when the function is\ndefined, in the scope that contains the function definition. The\nresult must be a callable, which is invoked with the function object\nas the only argument. The returned value is bound to the function name\ninstead of the function object. Multiple decorators are applied in\nnested fashion. For example, the following code\n\n @f1(arg)\n @f2\n def func(): pass\n\nis equivalent to\n\n def func(): pass\n func = f1(arg)(f2(func))\n\nWhen one or more parameters have the form *parameter* ``=``\n*expression*, the function is said to have "default parameter values."\nFor a parameter with a default value, the corresponding argument may\nbe omitted from a call, in which case the parameter\'s default value is\nsubstituted. If a parameter has a default value, all following\nparameters up until the "``*``" must also have a default value ---\nthis is a syntactic restriction that is not expressed by the grammar.\n\n**Default parameter values are evaluated when the function definition\nis executed.** This means that the expression is evaluated once, when\nthe function is defined, and that that same "pre-computed" value is\nused for each call. This is especially important to understand when a\ndefault parameter is a mutable object, such as a list or a dictionary:\nif the function modifies the object (e.g. by appending an item to a\nlist), the default value is in effect modified. This is generally not\nwhat was intended. A way around this is to use ``None`` as the\ndefault, and explicitly test for it in the body of the function, e.g.:\n\n def whats_on_the_telly(penguin=None):\n if penguin is None:\n penguin = []\n penguin.append("property of the zoo")\n return penguin\n\nFunction call semantics are described in more detail in section\n*Calls*. A function call always assigns values to all parameters\nmentioned in the parameter list, either from position arguments, from\nkeyword arguments, or from default values. If the form\n"``*identifier``" is present, it is initialized to a tuple receiving\nany excess positional parameters, defaulting to the empty tuple. If\nthe form "``**identifier``" is present, it is initialized to a new\ndictionary receiving any excess keyword arguments, defaulting to a new\nempty dictionary. Parameters after "``*``" or "``*identifier``" are\nkeyword-only parameters and may only be passed used keyword arguments.\n\nParameters may have annotations of the form "``: expression``"\nfollowing the parameter name. Any parameter may have an annotation\neven those of the form ``*identifier`` or ``**identifier``. Functions\nmay have "return" annotation of the form "``-> expression``" after the\nparameter list. These annotations can be any valid Python expression\nand are evaluated when the function definition is executed.\nAnnotations may be evaluated in a different order than they appear in\nthe source code. The presence of annotations does not change the\nsemantics of a function. The annotation values are available as\nvalues of a dictionary keyed by the parameters\' names in the\n``__annotations__`` attribute of the function object.\n\nIt is also possible to create anonymous functions (functions not bound\nto a name), for immediate use in expressions. This uses lambda forms,\ndescribed in section *Lambdas*. Note that the lambda form is merely a\nshorthand for a simplified function definition; a function defined in\na "``def``" statement can be passed around or assigned to another name\njust like a function defined by a lambda form. The "``def``" form is\nactually more powerful since it allows the execution of multiple\nstatements and annotations.\n\n**Programmer\'s note:** Functions are first-class objects. A "``def``"\nform executed inside a function definition defines a local function\nthat can be returned or passed around. Free variables used in the\nnested function can access the local variables of the function\ncontaining the def. See section *Naming and binding* for details.\n\n\nClass definitions\n=================\n\nA class definition defines a class object (see section *The standard\ntype hierarchy*):\n\n classdef ::= [decorators] "class" classname [inheritance] ":" suite\n inheritance ::= "(" [argument_list [","] | comprehension] ")"\n classname ::= identifier\n\nA class definition is an executable statement. The inheritance list\nusually gives a list of base classes (see *Customizing class creation*\nfor more advanced uses), so each item in the list should evaluate to a\nclass object which allows subclassing. Classes without an inheritance\nlist inherit, by default, from the base class ``object``; hence,\n\n class Foo:\n pass\n\nis equivalent to\n\n class Foo(object):\n pass\n\nThe class\'s suite is then executed in a new execution frame (see\n*Naming and binding*), using a newly created local namespace and the\noriginal global namespace. (Usually, the suite contains mostly\nfunction definitions.) When the class\'s suite finishes execution, its\nexecution frame is discarded but its local namespace is saved. [4] A\nclass object is then created using the inheritance list for the base\nclasses and the saved local namespace for the attribute dictionary.\nThe class name is bound to this class object in the original local\nnamespace.\n\nClass creation can be customized heavily using *metaclasses*.\n\nClasses can also be decorated: just like when decorating functions,\n\n @f1(arg)\n @f2\n class Foo: pass\n\nis equivalent to\n\n class Foo: pass\n Foo = f1(arg)(f2(Foo))\n\nThe evaluation rules for the decorator expressions are the same as for\nfunction decorators. The result must be a class object, which is then\nbound to the class name.\n\n**Programmer\'s note:** Variables defined in the class definition are\nclass attributes; they are shared by instances. Instance attributes\ncan be set in a method with ``self.name = value``. Both class and\ninstance attributes are accessible through the notation\n"``self.name``", and an instance attribute hides a class attribute\nwith the same name when accessed in this way. Class attributes can be\nused as defaults for instance attributes, but using mutable values\nthere can lead to unexpected results. *Descriptors* can be used to\ncreate instance variables with different implementation details.\n\nSee also:\n\n **PEP 3116** - Metaclasses in Python 3 **PEP 3129** - Class\n Decorators\n\n-[ Footnotes ]-\n\n[1] The exception is propagated to the invocation stack only if there\n is no ``finally`` clause that negates the exception.\n\n[2] Currently, control "flows off the end" except in the case of an\n exception or the execution of a ``return``, ``continue``, or\n ``break`` statement.\n\n[3] A string literal appearing as the first statement in the function\n body is transformed into the function\'s ``__doc__`` attribute and\n therefore the function\'s *docstring*.\n\n[4] A string literal appearing as the first statement in the class\n body is transformed into the namespace\'s ``__doc__`` item and\n therefore the class\'s *docstring*.\n', + 'compound': '\nCompound statements\n*******************\n\nCompound statements contain (groups of) other statements; they affect\nor control the execution of those other statements in some way. In\ngeneral, compound statements span multiple lines, although in simple\nincarnations a whole compound statement may be contained in one line.\n\nThe ``if``, ``while`` and ``for`` statements implement traditional\ncontrol flow constructs. ``try`` specifies exception handlers and/or\ncleanup code for a group of statements, while the ``with`` statement\nallows the execution of initialization and finalization code around a\nblock of code. Function and class definitions are also syntactically\ncompound statements.\n\nCompound statements consist of one or more \'clauses.\' A clause\nconsists of a header and a \'suite.\' The clause headers of a\nparticular compound statement are all at the same indentation level.\nEach clause header begins with a uniquely identifying keyword and ends\nwith a colon. A suite is a group of statements controlled by a\nclause. A suite can be one or more semicolon-separated simple\nstatements on the same line as the header, following the header\'s\ncolon, or it can be one or more indented statements on subsequent\nlines. Only the latter form of suite can contain nested compound\nstatements; the following is illegal, mostly because it wouldn\'t be\nclear to which ``if`` clause a following ``else`` clause would belong:\n\n if test1: if test2: print(x)\n\nAlso note that the semicolon binds tighter than the colon in this\ncontext, so that in the following example, either all or none of the\n``print()`` calls are executed:\n\n if x < y < z: print(x); print(y); print(z)\n\nSummarizing:\n\n compound_stmt ::= if_stmt\n | while_stmt\n | for_stmt\n | try_stmt\n | with_stmt\n | funcdef\n | classdef\n suite ::= stmt_list NEWLINE | NEWLINE INDENT statement+ DEDENT\n statement ::= stmt_list NEWLINE | compound_stmt\n stmt_list ::= simple_stmt (";" simple_stmt)* [";"]\n\nNote that statements always end in a ``NEWLINE`` possibly followed by\na ``DEDENT``. Also note that optional continuation clauses always\nbegin with a keyword that cannot start a statement, thus there are no\nambiguities (the \'dangling ``else``\' problem is solved in Python by\nrequiring nested ``if`` statements to be indented).\n\nThe formatting of the grammar rules in the following sections places\neach clause on a separate line for clarity.\n\n\nThe ``if`` statement\n====================\n\nThe ``if`` statement is used for conditional execution:\n\n if_stmt ::= "if" expression ":" suite\n ( "elif" expression ":" suite )*\n ["else" ":" suite]\n\nIt selects exactly one of the suites by evaluating the expressions one\nby one until one is found to be true (see section *Boolean operations*\nfor the definition of true and false); then that suite is executed\n(and no other part of the ``if`` statement is executed or evaluated).\nIf all expressions are false, the suite of the ``else`` clause, if\npresent, is executed.\n\n\nThe ``while`` statement\n=======================\n\nThe ``while`` statement is used for repeated execution as long as an\nexpression is true:\n\n while_stmt ::= "while" expression ":" suite\n ["else" ":" suite]\n\nThis repeatedly tests the expression and, if it is true, executes the\nfirst suite; if the expression is false (which may be the first time\nit is tested) the suite of the ``else`` clause, if present, is\nexecuted and the loop terminates.\n\nA ``break`` statement executed in the first suite terminates the loop\nwithout executing the ``else`` clause\'s suite. A ``continue``\nstatement executed in the first suite skips the rest of the suite and\ngoes back to testing the expression.\n\n\nThe ``for`` statement\n=====================\n\nThe ``for`` statement is used to iterate over the elements of a\nsequence (such as a string, tuple or list) or other iterable object:\n\n for_stmt ::= "for" target_list "in" expression_list ":" suite\n ["else" ":" suite]\n\nThe expression list is evaluated once; it should yield an iterable\nobject. An iterator is created for the result of the\n``expression_list``. The suite is then executed once for each item\nprovided by the iterator, in the order of ascending indices. Each\nitem in turn is assigned to the target list using the standard rules\nfor assignments (see *Assignment statements*), and then the suite is\nexecuted. When the items are exhausted (which is immediately when the\nsequence is empty or an iterator raises a ``StopIteration``\nexception), the suite in the ``else`` clause, if present, is executed,\nand the loop terminates.\n\nA ``break`` statement executed in the first suite terminates the loop\nwithout executing the ``else`` clause\'s suite. A ``continue``\nstatement executed in the first suite skips the rest of the suite and\ncontinues with the next item, or with the ``else`` clause if there was\nno next item.\n\nThe suite may assign to the variable(s) in the target list; this does\nnot affect the next item assigned to it.\n\nNames in the target list are not deleted when the loop is finished,\nbut if the sequence is empty, it will not have been assigned to at all\nby the loop. Hint: the built-in function ``range()`` returns an\niterator of integers suitable to emulate the effect of Pascal\'s ``for\ni := a to b do``; e.g., ``list(range(3))`` returns the list ``[0, 1,\n2]``.\n\nNote: There is a subtlety when the sequence is being modified by the loop\n (this can only occur for mutable sequences, i.e. lists). An\n internal counter is used to keep track of which item is used next,\n and this is incremented on each iteration. When this counter has\n reached the length of the sequence the loop terminates. This means\n that if the suite deletes the current (or a previous) item from the\n sequence, the next item will be skipped (since it gets the index of\n the current item which has already been treated). Likewise, if the\n suite inserts an item in the sequence before the current item, the\n current item will be treated again the next time through the loop.\n This can lead to nasty bugs that can be avoided by making a\n temporary copy using a slice of the whole sequence, e.g.,\n\n for x in a[:]:\n if x < 0: a.remove(x)\n\n\nThe ``try`` statement\n=====================\n\nThe ``try`` statement specifies exception handlers and/or cleanup code\nfor a group of statements:\n\n try_stmt ::= try1_stmt | try2_stmt\n try1_stmt ::= "try" ":" suite\n ("except" [expression ["as" target]] ":" suite)+\n ["else" ":" suite]\n ["finally" ":" suite]\n try2_stmt ::= "try" ":" suite\n "finally" ":" suite\n\nThe ``except`` clause(s) specify one or more exception handlers. When\nno exception occurs in the ``try`` clause, no exception handler is\nexecuted. When an exception occurs in the ``try`` suite, a search for\nan exception handler is started. This search inspects the except\nclauses in turn until one is found that matches the exception. An\nexpression-less except clause, if present, must be last; it matches\nany exception. For an except clause with an expression, that\nexpression is evaluated, and the clause matches the exception if the\nresulting object is "compatible" with the exception. An object is\ncompatible with an exception if it is the class or a base class of the\nexception object or a tuple containing an item compatible with the\nexception.\n\nIf no except clause matches the exception, the search for an exception\nhandler continues in the surrounding code and on the invocation stack.\n[1]\n\nIf the evaluation of an expression in the header of an except clause\nraises an exception, the original search for a handler is canceled and\na search starts for the new exception in the surrounding code and on\nthe call stack (it is treated as if the entire ``try`` statement\nraised the exception).\n\nWhen a matching except clause is found, the exception is assigned to\nthe target specified after the ``as`` keyword in that except clause,\nif present, and the except clause\'s suite is executed. All except\nclauses must have an executable block. When the end of this block is\nreached, execution continues normally after the entire try statement.\n(This means that if two nested handlers exist for the same exception,\nand the exception occurs in the try clause of the inner handler, the\nouter handler will not handle the exception.)\n\nWhen an exception has been assigned using ``as target``, it is cleared\nat the end of the except clause. This is as if\n\n except E as N:\n foo\n\nwas translated to\n\n except E as N:\n try:\n foo\n finally:\n del N\n\nThis means the exception must be assigned to a different name to be\nable to refer to it after the except clause. Exceptions are cleared\nbecause with the traceback attached to them, they form a reference\ncycle with the stack frame, keeping all locals in that frame alive\nuntil the next garbage collection occurs.\n\nBefore an except clause\'s suite is executed, details about the\nexception are stored in the ``sys`` module and can be access via\n``sys.exc_info()``. ``sys.exc_info()`` returns a 3-tuple consisting of\nthe exception class, the exception instance and a traceback object\n(see section *The standard type hierarchy*) identifying the point in\nthe program where the exception occurred. ``sys.exc_info()`` values\nare restored to their previous values (before the call) when returning\nfrom a function that handled an exception.\n\nThe optional ``else`` clause is executed if and when control flows off\nthe end of the ``try`` clause. [2] Exceptions in the ``else`` clause\nare not handled by the preceding ``except`` clauses.\n\nIf ``finally`` is present, it specifies a \'cleanup\' handler. The\n``try`` clause is executed, including any ``except`` and ``else``\nclauses. If an exception occurs in any of the clauses and is not\nhandled, the exception is temporarily saved. The ``finally`` clause is\nexecuted. If there is a saved exception, it is re-raised at the end\nof the ``finally`` clause. If the ``finally`` clause raises another\nexception or executes a ``return`` or ``break`` statement, the saved\nexception is lost. The exception information is not available to the\nprogram during execution of the ``finally`` clause.\n\nWhen a ``return``, ``break`` or ``continue`` statement is executed in\nthe ``try`` suite of a ``try``...``finally`` statement, the\n``finally`` clause is also executed \'on the way out.\' A ``continue``\nstatement is illegal in the ``finally`` clause. (The reason is a\nproblem with the current implementation --- this restriction may be\nlifted in the future).\n\nAdditional information on exceptions can be found in section\n*Exceptions*, and information on using the ``raise`` statement to\ngenerate exceptions may be found in section *The raise statement*.\n\n\nThe ``with`` statement\n======================\n\nThe ``with`` statement is used to wrap the execution of a block with\nmethods defined by a context manager (see section *With Statement\nContext Managers*). This allows common\n``try``...``except``...``finally`` usage patterns to be encapsulated\nfor convenient reuse.\n\n with_stmt ::= "with" with_item ("," with_item)* ":" suite\n with_item ::= expression ["as" target]\n\nThe execution of the ``with`` statement with one "item" proceeds as\nfollows:\n\n1. The context expression (the expression given in the ``with_item``)\n is evaluated to obtain a context manager.\n\n2. The context manager\'s ``__exit__()`` is loaded for later use.\n\n3. The context manager\'s ``__enter__()`` method is invoked.\n\n4. If a target was included in the ``with`` statement, the return\n value from ``__enter__()`` is assigned to it.\n\n Note: The ``with`` statement guarantees that if the ``__enter__()``\n method returns without an error, then ``__exit__()`` will always\n be called. Thus, if an error occurs during the assignment to the\n target list, it will be treated the same as an error occurring\n within the suite would be. See step 6 below.\n\n5. The suite is executed.\n\n6. The context manager\'s ``__exit__()`` method is invoked. If an\n exception caused the suite to be exited, its type, value, and\n traceback are passed as arguments to ``__exit__()``. Otherwise,\n three ``None`` arguments are supplied.\n\n If the suite was exited due to an exception, and the return value\n from the ``__exit__()`` method was false, the exception is\n reraised. If the return value was true, the exception is\n suppressed, and execution continues with the statement following\n the ``with`` statement.\n\n If the suite was exited for any reason other than an exception, the\n return value from ``__exit__()`` is ignored, and execution proceeds\n at the normal location for the kind of exit that was taken.\n\nWith more than one item, the context managers are processed as if\nmultiple ``with`` statements were nested:\n\n with A() as a, B() as b:\n suite\n\nis equivalent to\n\n with A() as a:\n with B() as b:\n suite\n\nChanged in version 3.1: Support for multiple context expressions.\n\nSee also:\n\n **PEP 0343** - The "with" statement\n The specification, background, and examples for the Python\n ``with`` statement.\n\n\nFunction definitions\n====================\n\nA function definition defines a user-defined function object (see\nsection *The standard type hierarchy*):\n\n funcdef ::= [decorators] "def" funcname "(" [parameter_list] ")" ["->" expression] ":" suite\n decorators ::= decorator+\n decorator ::= "@" dotted_name ["(" [argument_list [","]] ")"] NEWLINE\n dotted_name ::= identifier ("." identifier)*\n parameter_list ::= (defparameter ",")*\n ( "*" [parameter] ("," defparameter)*\n [, "**" parameter]\n | "**" parameter\n | defparameter [","] )\n parameter ::= identifier [":" expression]\n defparameter ::= parameter ["=" expression]\n funcname ::= identifier\n\nA function definition is an executable statement. Its execution binds\nthe function name in the current local namespace to a function object\n(a wrapper around the executable code for the function). This\nfunction object contains a reference to the current global namespace\nas the global namespace to be used when the function is called.\n\nThe function definition does not execute the function body; this gets\nexecuted only when the function is called. [3]\n\nA function definition may be wrapped by one or more *decorator*\nexpressions. Decorator expressions are evaluated when the function is\ndefined, in the scope that contains the function definition. The\nresult must be a callable, which is invoked with the function object\nas the only argument. The returned value is bound to the function name\ninstead of the function object. Multiple decorators are applied in\nnested fashion. For example, the following code\n\n @f1(arg)\n @f2\n def func(): pass\n\nis equivalent to\n\n def func(): pass\n func = f1(arg)(f2(func))\n\nWhen one or more parameters have the form *parameter* ``=``\n*expression*, the function is said to have "default parameter values."\nFor a parameter with a default value, the corresponding argument may\nbe omitted from a call, in which case the parameter\'s default value is\nsubstituted. If a parameter has a default value, all following\nparameters up until the "``*``" must also have a default value ---\nthis is a syntactic restriction that is not expressed by the grammar.\n\n**Default parameter values are evaluated when the function definition\nis executed.** This means that the expression is evaluated once, when\nthe function is defined, and that that same "pre-computed" value is\nused for each call. This is especially important to understand when a\ndefault parameter is a mutable object, such as a list or a dictionary:\nif the function modifies the object (e.g. by appending an item to a\nlist), the default value is in effect modified. This is generally not\nwhat was intended. A way around this is to use ``None`` as the\ndefault, and explicitly test for it in the body of the function, e.g.:\n\n def whats_on_the_telly(penguin=None):\n if penguin is None:\n penguin = []\n penguin.append("property of the zoo")\n return penguin\n\nFunction call semantics are described in more detail in section\n*Calls*. A function call always assigns values to all parameters\nmentioned in the parameter list, either from position arguments, from\nkeyword arguments, or from default values. If the form\n"``*identifier``" is present, it is initialized to a tuple receiving\nany excess positional parameters, defaulting to the empty tuple. If\nthe form "``**identifier``" is present, it is initialized to a new\ndictionary receiving any excess keyword arguments, defaulting to a new\nempty dictionary. Parameters after "``*``" or "``*identifier``" are\nkeyword-only parameters and may only be passed used keyword arguments.\n\nParameters may have annotations of the form "``: expression``"\nfollowing the parameter name. Any parameter may have an annotation\neven those of the form ``*identifier`` or ``**identifier``. Functions\nmay have "return" annotation of the form "``-> expression``" after the\nparameter list. These annotations can be any valid Python expression\nand are evaluated when the function definition is executed.\nAnnotations may be evaluated in a different order than they appear in\nthe source code. The presence of annotations does not change the\nsemantics of a function. The annotation values are available as\nvalues of a dictionary keyed by the parameters\' names in the\n``__annotations__`` attribute of the function object.\n\nIt is also possible to create anonymous functions (functions not bound\nto a name), for immediate use in expressions. This uses lambda forms,\ndescribed in section *Lambdas*. Note that the lambda form is merely a\nshorthand for a simplified function definition; a function defined in\na "``def``" statement can be passed around or assigned to another name\njust like a function defined by a lambda form. The "``def``" form is\nactually more powerful since it allows the execution of multiple\nstatements and annotations.\n\n**Programmer\'s note:** Functions are first-class objects. A "``def``"\nform executed inside a function definition defines a local function\nthat can be returned or passed around. Free variables used in the\nnested function can access the local variables of the function\ncontaining the def. See section *Naming and binding* for details.\n\n\nClass definitions\n=================\n\nA class definition defines a class object (see section *The standard\ntype hierarchy*):\n\n classdef ::= [decorators] "class" classname [inheritance] ":" suite\n inheritance ::= "(" [argument_list [","] | comprehension] ")"\n classname ::= identifier\n\nA class definition is an executable statement. The inheritance list\nusually gives a list of base classes (see *Customizing class creation*\nfor more advanced uses), so each item in the list should evaluate to a\nclass object which allows subclassing. Classes without an inheritance\nlist inherit, by default, from the base class ``object``; hence,\n\n class Foo:\n pass\n\nis equivalent to\n\n class Foo(object):\n pass\n\nThe class\'s suite is then executed in a new execution frame (see\n*Naming and binding*), using a newly created local namespace and the\noriginal global namespace. (Usually, the suite contains mostly\nfunction definitions.) When the class\'s suite finishes execution, its\nexecution frame is discarded but its local namespace is saved. [4] A\nclass object is then created using the inheritance list for the base\nclasses and the saved local namespace for the attribute dictionary.\nThe class name is bound to this class object in the original local\nnamespace.\n\nClass creation can be customized heavily using *metaclasses*.\n\nClasses can also be decorated: just like when decorating functions,\n\n @f1(arg)\n @f2\n class Foo: pass\n\nis equivalent to\n\n class Foo: pass\n Foo = f1(arg)(f2(Foo))\n\nThe evaluation rules for the decorator expressions are the same as for\nfunction decorators. The result must be a class object, which is then\nbound to the class name.\n\n**Programmer\'s note:** Variables defined in the class definition are\nclass attributes; they are shared by instances. Instance attributes\ncan be set in a method with ``self.name = value``. Both class and\ninstance attributes are accessible through the notation\n"``self.name``", and an instance attribute hides a class attribute\nwith the same name when accessed in this way. Class attributes can be\nused as defaults for instance attributes, but using mutable values\nthere can lead to unexpected results. *Descriptors* can be used to\ncreate instance variables with different implementation details.\n\nSee also:\n\n **PEP 3115** - Metaclasses in Python 3 **PEP 3129** - Class\n Decorators\n\n-[ Footnotes ]-\n\n[1] The exception is propagated to the invocation stack only if there\n is no ``finally`` clause that negates the exception.\n\n[2] Currently, control "flows off the end" except in the case of an\n exception or the execution of a ``return``, ``continue``, or\n ``break`` statement.\n\n[3] A string literal appearing as the first statement in the function\n body is transformed into the function\'s ``__doc__`` attribute and\n therefore the function\'s *docstring*.\n\n[4] A string literal appearing as the first statement in the class\n body is transformed into the namespace\'s ``__doc__`` item and\n therefore the class\'s *docstring*.\n', 'context-managers': '\nWith Statement Context Managers\n*******************************\n\nA *context manager* is an object that defines the runtime context to\nbe established when executing a ``with`` statement. The context\nmanager handles the entry into, and the exit from, the desired runtime\ncontext for the execution of the block of code. Context managers are\nnormally invoked using the ``with`` statement (described in section\n*The with statement*), but can also be used by directly invoking their\nmethods.\n\nTypical uses of context managers include saving and restoring various\nkinds of global state, locking and unlocking resources, closing opened\nfiles, etc.\n\nFor more information on context managers, see *Context Manager Types*.\n\nobject.__enter__(self)\n\n Enter the runtime context related to this object. The ``with``\n statement will bind this method\'s return value to the target(s)\n specified in the ``as`` clause of the statement, if any.\n\nobject.__exit__(self, exc_type, exc_value, traceback)\n\n Exit the runtime context related to this object. The parameters\n describe the exception that caused the context to be exited. If the\n context was exited without an exception, all three arguments will\n be ``None``.\n\n If an exception is supplied, and the method wishes to suppress the\n exception (i.e., prevent it from being propagated), it should\n return a true value. Otherwise, the exception will be processed\n normally upon exit from this method.\n\n Note that ``__exit__()`` methods should not reraise the passed-in\n exception; this is the caller\'s responsibility.\n\nSee also:\n\n **PEP 0343** - The "with" statement\n The specification, background, and examples for the Python\n ``with`` statement.\n', 'continue': '\nThe ``continue`` statement\n**************************\n\n continue_stmt ::= "continue"\n\n``continue`` may only occur syntactically nested in a ``for`` or\n``while`` loop, but not nested in a function or class definition or\n``finally`` clause within that loop. It continues with the next cycle\nof the nearest enclosing loop.\n\nWhen ``continue`` passes control out of a ``try`` statement with a\n``finally`` clause, that ``finally`` clause is executed before really\nstarting the next loop cycle.\n', 'conversions': '\nArithmetic conversions\n**********************\n\nWhen a description of an arithmetic operator below uses the phrase\n"the numeric arguments are converted to a common type," this means\nthat the operator implementation for built-in types works that way:\n\n* If either argument is a complex number, the other is converted to\n complex;\n\n* otherwise, if either argument is a floating point number, the other\n is converted to floating point;\n\n* otherwise, both must be integers and no conversion is necessary.\n\nSome additional rules apply for certain operators (e.g., a string left\nargument to the \'%\' operator). Extensions must define their own\nconversion behavior.\n', @@ -29,7 +29,7 @@ 'dynamic-features': '\nInteraction with dynamic features\n*********************************\n\nThere are several cases where Python statements are illegal when used\nin conjunction with nested scopes that contain free variables.\n\nIf a variable is referenced in an enclosing scope, it is illegal to\ndelete the name. An error will be reported at compile time.\n\nIf the wild card form of import --- ``import *`` --- is used in a\nfunction and the function contains or is a nested block with free\nvariables, the compiler will raise a ``SyntaxError``.\n\nThe ``eval()`` and ``exec()`` functions do not have access to the full\nenvironment for resolving names. Names may be resolved in the local\nand global namespaces of the caller. Free variables are not resolved\nin the nearest enclosing namespace, but in the global namespace. [1]\nThe ``exec()`` and ``eval()`` functions have optional arguments to\noverride the global and local namespace. If only one namespace is\nspecified, it is used for both.\n', 'else': '\nThe ``if`` statement\n********************\n\nThe ``if`` statement is used for conditional execution:\n\n if_stmt ::= "if" expression ":" suite\n ( "elif" expression ":" suite )*\n ["else" ":" suite]\n\nIt selects exactly one of the suites by evaluating the expressions one\nby one until one is found to be true (see section *Boolean operations*\nfor the definition of true and false); then that suite is executed\n(and no other part of the ``if`` statement is executed or evaluated).\nIf all expressions are false, the suite of the ``else`` clause, if\npresent, is executed.\n', 'exceptions': '\nExceptions\n**********\n\nExceptions are a means of breaking out of the normal flow of control\nof a code block in order to handle errors or other exceptional\nconditions. An exception is *raised* at the point where the error is\ndetected; it may be *handled* by the surrounding code block or by any\ncode block that directly or indirectly invoked the code block where\nthe error occurred.\n\nThe Python interpreter raises an exception when it detects a run-time\nerror (such as division by zero). A Python program can also\nexplicitly raise an exception with the ``raise`` statement. Exception\nhandlers are specified with the ``try`` ... ``except`` statement. The\n``finally`` clause of such a statement can be used to specify cleanup\ncode which does not handle the exception, but is executed whether an\nexception occurred or not in the preceding code.\n\nPython uses the "termination" model of error handling: an exception\nhandler can find out what happened and continue execution at an outer\nlevel, but it cannot repair the cause of the error and retry the\nfailing operation (except by re-entering the offending piece of code\nfrom the top).\n\nWhen an exception is not handled at all, the interpreter terminates\nexecution of the program, or returns to its interactive main loop. In\neither case, it prints a stack backtrace, except when the exception is\n``SystemExit``.\n\nExceptions are identified by class instances. The ``except`` clause\nis selected depending on the class of the instance: it must reference\nthe class of the instance or a base class thereof. The instance can\nbe received by the handler and can carry additional information about\nthe exceptional condition.\n\nNote: Exception messages are not part of the Python API. Their contents\n may change from one version of Python to the next without warning\n and should not be relied on by code which will run under multiple\n versions of the interpreter.\n\nSee also the description of the ``try`` statement in section *The try\nstatement* and ``raise`` statement in section *The raise statement*.\n\n-[ Footnotes ]-\n\n[1] This limitation occurs because the code that is executed by these\n operations is not available at the time the module is compiled.\n', - 'execmodel': '\nExecution model\n***************\n\n\nNaming and binding\n==================\n\n*Names* refer to objects. Names are introduced by name binding\noperations. Each occurrence of a name in the program text refers to\nthe *binding* of that name established in the innermost function block\ncontaining the use.\n\nA *block* is a piece of Python program text that is executed as a\nunit. The following are blocks: a module, a function body, and a class\ndefinition. Each command typed interactively is a block. A script\nfile (a file given as standard input to the interpreter or specified\non the interpreter command line the first argument) is a code block.\nA script command (a command specified on the interpreter command line\nwith the \'**-c**\' option) is a code block. The string argument passed\nto the built-in functions ``eval()`` and ``exec()`` is a code block.\n\nA code block is executed in an *execution frame*. A frame contains\nsome administrative information (used for debugging) and determines\nwhere and how execution continues after the code block\'s execution has\ncompleted.\n\nA *scope* defines the visibility of a name within a block. If a local\nvariable is defined in a block, its scope includes that block. If the\ndefinition occurs in a function block, the scope extends to any blocks\ncontained within the defining one, unless a contained block introduces\na different binding for the name. The scope of names defined in a\nclass block is limited to the class block; it does not extend to the\ncode blocks of methods -- this includes comprehensions and generator\nexpressions since they are implemented using a function scope. This\nmeans that the following will fail:\n\n class A:\n a = 42\n b = list(a + i for i in range(10))\n\nWhen a name is used in a code block, it is resolved using the nearest\nenclosing scope. The set of all such scopes visible to a code block\nis called the block\'s *environment*.\n\nIf a name is bound in a block, it is a local variable of that block,\nunless declared as ``nonlocal``. If a name is bound at the module\nlevel, it is a global variable. (The variables of the module code\nblock are local and global.) If a variable is used in a code block\nbut not defined there, it is a *free variable*.\n\nWhen a name is not found at all, a ``NameError`` exception is raised.\nIf the name refers to a local variable that has not been bound, a\n``UnboundLocalError`` exception is raised. ``UnboundLocalError`` is a\nsubclass of ``NameError``.\n\nThe following constructs bind names: formal parameters to functions,\n``import`` statements, class and function definitions (these bind the\nclass or function name in the defining block), and targets that are\nidentifiers if occurring in an assignment, ``for`` loop header, or\nafter ``as`` in a ``with`` statement or ``except`` clause. The\n``import`` statement of the form ``from ... import *`` binds all names\ndefined in the imported module, except those beginning with an\nunderscore. This form may only be used at the module level.\n\nA target occurring in a ``del`` statement is also considered bound for\nthis purpose (though the actual semantics are to unbind the name). It\nis illegal to unbind a name that is referenced by an enclosing scope;\nthe compiler will report a ``SyntaxError``.\n\nEach assignment or import statement occurs within a block defined by a\nclass or function definition or at the module level (the top-level\ncode block).\n\nIf a name binding operation occurs anywhere within a code block, all\nuses of the name within the block are treated as references to the\ncurrent block. This can lead to errors when a name is used within a\nblock before it is bound. This rule is subtle. Python lacks\ndeclarations and allows name binding operations to occur anywhere\nwithin a code block. The local variables of a code block can be\ndetermined by scanning the entire text of the block for name binding\noperations.\n\nIf the ``global`` statement occurs within a block, all uses of the\nname specified in the statement refer to the binding of that name in\nthe top-level namespace. Names are resolved in the top-level\nnamespace by searching the global namespace, i.e. the namespace of the\nmodule containing the code block, and the builtins namespace, the\nnamespace of the module ``builtins``. The global namespace is\nsearched first. If the name is not found there, the builtins\nnamespace is searched. The global statement must precede all uses of\nthe name.\n\nThe builtins namespace associated with the execution of a code block\nis actually found by looking up the name ``__builtins__`` in its\nglobal namespace; this should be a dictionary or a module (in the\nlatter case the module\'s dictionary is used). By default, when in the\n``__main__`` module, ``__builtins__`` is the built-in module\n``builtins``; when in any other module, ``__builtins__`` is an alias\nfor the dictionary of the ``builtins`` module itself.\n``__builtins__`` can be set to a user-created dictionary to create a\nweak form of restricted execution.\n\n**CPython implementation detail:** Users should not touch\n``__builtins__``; it is strictly an implementation detail. Users\nwanting to override values in the builtins namespace should ``import``\nthe ``builtins`` module and modify its attributes appropriately.\n\nThe namespace for a module is automatically created the first time a\nmodule is imported. The main module for a script is always called\n``__main__``.\n\nThe ``global`` statement has the same scope as a name binding\noperation in the same block. If the nearest enclosing scope for a\nfree variable contains a global statement, the free variable is\ntreated as a global.\n\nA class definition is an executable statement that may use and define\nnames. These references follow the normal rules for name resolution.\nThe namespace of the class definition becomes the attribute dictionary\nof the class. Names defined at the class scope are not visible in\nmethods.\n\n\nInteraction with dynamic features\n---------------------------------\n\nThere are several cases where Python statements are illegal when used\nin conjunction with nested scopes that contain free variables.\n\nIf a variable is referenced in an enclosing scope, it is illegal to\ndelete the name. An error will be reported at compile time.\n\nIf the wild card form of import --- ``import *`` --- is used in a\nfunction and the function contains or is a nested block with free\nvariables, the compiler will raise a ``SyntaxError``.\n\nThe ``eval()`` and ``exec()`` functions do not have access to the full\nenvironment for resolving names. Names may be resolved in the local\nand global namespaces of the caller. Free variables are not resolved\nin the nearest enclosing namespace, but in the global namespace. [1]\nThe ``exec()`` and ``eval()`` functions have optional arguments to\noverride the global and local namespace. If only one namespace is\nspecified, it is used for both.\n\n\nExceptions\n==========\n\nExceptions are a means of breaking out of the normal flow of control\nof a code block in order to handle errors or other exceptional\nconditions. An exception is *raised* at the point where the error is\ndetected; it may be *handled* by the surrounding code block or by any\ncode block that directly or indirectly invoked the code block where\nthe error occurred.\n\nThe Python interpreter raises an exception when it detects a run-time\nerror (such as division by zero). A Python program can also\nexplicitly raise an exception with the ``raise`` statement. Exception\nhandlers are specified with the ``try`` ... ``except`` statement. The\n``finally`` clause of such a statement can be used to specify cleanup\ncode which does not handle the exception, but is executed whether an\nexception occurred or not in the preceding code.\n\nPython uses the "termination" model of error handling: an exception\nhandler can find out what happened and continue execution at an outer\nlevel, but it cannot repair the cause of the error and retry the\nfailing operation (except by re-entering the offending piece of code\nfrom the top).\n\nWhen an exception is not handled at all, the interpreter terminates\nexecution of the program, or returns to its interactive main loop. In\neither case, it prints a stack backtrace, except when the exception is\n``SystemExit``.\n\nExceptions are identified by class instances. The ``except`` clause\nis selected depending on the class of the instance: it must reference\nthe class of the instance or a base class thereof. The instance can\nbe received by the handler and can carry additional information about\nthe exceptional condition.\n\nNote: Exception messages are not part of the Python API. Their contents\n may change from one version of Python to the next without warning\n and should not be relied on by code which will run under multiple\n versions of the interpreter.\n\nSee also the description of the ``try`` statement in section *The try\nstatement* and ``raise`` statement in section *The raise statement*.\n\n-[ Footnotes ]-\n\n[1] This limitation occurs because the code that is executed by these\n operations is not available at the time the module is compiled.\n', + 'execmodel': '\nExecution model\n***************\n\n\nNaming and binding\n==================\n\n*Names* refer to objects. Names are introduced by name binding\noperations. Each occurrence of a name in the program text refers to\nthe *binding* of that name established in the innermost function block\ncontaining the use.\n\nA *block* is a piece of Python program text that is executed as a\nunit. The following are blocks: a module, a function body, and a class\ndefinition. Each command typed interactively is a block. A script\nfile (a file given as standard input to the interpreter or specified\non the interpreter command line the first argument) is a code block.\nA script command (a command specified on the interpreter command line\nwith the \'**-c**\' option) is a code block. The string argument passed\nto the built-in functions ``eval()`` and ``exec()`` is a code block.\n\nA code block is executed in an *execution frame*. A frame contains\nsome administrative information (used for debugging) and determines\nwhere and how execution continues after the code block\'s execution has\ncompleted.\n\nA *scope* defines the visibility of a name within a block. If a local\nvariable is defined in a block, its scope includes that block. If the\ndefinition occurs in a function block, the scope extends to any blocks\ncontained within the defining one, unless a contained block introduces\na different binding for the name. The scope of names defined in a\nclass block is limited to the class block; it does not extend to the\ncode blocks of methods -- this includes comprehensions and generator\nexpressions since they are implemented using a function scope. This\nmeans that the following will fail:\n\n class A:\n a = 42\n b = list(a + i for i in range(10))\n\nWhen a name is used in a code block, it is resolved using the nearest\nenclosing scope. The set of all such scopes visible to a code block\nis called the block\'s *environment*.\n\nIf a name is bound in a block, it is a local variable of that block,\nunless declared as ``nonlocal``. If a name is bound at the module\nlevel, it is a global variable. (The variables of the module code\nblock are local and global.) If a variable is used in a code block\nbut not defined there, it is a *free variable*.\n\nWhen a name is not found at all, a ``NameError`` exception is raised.\nIf the name refers to a local variable that has not been bound, a\n``UnboundLocalError`` exception is raised. ``UnboundLocalError`` is a\nsubclass of ``NameError``.\n\nThe following constructs bind names: formal parameters to functions,\n``import`` statements, class and function definitions (these bind the\nclass or function name in the defining block), and targets that are\nidentifiers if occurring in an assignment, ``for`` loop header, or\nafter ``as`` in a ``with`` statement or ``except`` clause. The\n``import`` statement of the form ``from ... import *`` binds all names\ndefined in the imported module, except those beginning with an\nunderscore. This form may only be used at the module level.\n\nA target occurring in a ``del`` statement is also considered bound for\nthis purpose (though the actual semantics are to unbind the name).\n\nEach assignment or import statement occurs within a block defined by a\nclass or function definition or at the module level (the top-level\ncode block).\n\nIf a name binding operation occurs anywhere within a code block, all\nuses of the name within the block are treated as references to the\ncurrent block. This can lead to errors when a name is used within a\nblock before it is bound. This rule is subtle. Python lacks\ndeclarations and allows name binding operations to occur anywhere\nwithin a code block. The local variables of a code block can be\ndetermined by scanning the entire text of the block for name binding\noperations.\n\nIf the ``global`` statement occurs within a block, all uses of the\nname specified in the statement refer to the binding of that name in\nthe top-level namespace. Names are resolved in the top-level\nnamespace by searching the global namespace, i.e. the namespace of the\nmodule containing the code block, and the builtins namespace, the\nnamespace of the module ``builtins``. The global namespace is\nsearched first. If the name is not found there, the builtins\nnamespace is searched. The global statement must precede all uses of\nthe name.\n\nThe builtins namespace associated with the execution of a code block\nis actually found by looking up the name ``__builtins__`` in its\nglobal namespace; this should be a dictionary or a module (in the\nlatter case the module\'s dictionary is used). By default, when in the\n``__main__`` module, ``__builtins__`` is the built-in module\n``builtins``; when in any other module, ``__builtins__`` is an alias\nfor the dictionary of the ``builtins`` module itself.\n``__builtins__`` can be set to a user-created dictionary to create a\nweak form of restricted execution.\n\n**CPython implementation detail:** Users should not touch\n``__builtins__``; it is strictly an implementation detail. Users\nwanting to override values in the builtins namespace should ``import``\nthe ``builtins`` module and modify its attributes appropriately.\n\nThe namespace for a module is automatically created the first time a\nmodule is imported. The main module for a script is always called\n``__main__``.\n\nThe ``global`` statement has the same scope as a name binding\noperation in the same block. If the nearest enclosing scope for a\nfree variable contains a global statement, the free variable is\ntreated as a global.\n\nA class definition is an executable statement that may use and define\nnames. These references follow the normal rules for name resolution.\nThe namespace of the class definition becomes the attribute dictionary\nof the class. Names defined at the class scope are not visible in\nmethods.\n\n\nInteraction with dynamic features\n---------------------------------\n\nThere are several cases where Python statements are illegal when used\nin conjunction with nested scopes that contain free variables.\n\nIf a variable is referenced in an enclosing scope, it is illegal to\ndelete the name. An error will be reported at compile time.\n\nIf the wild card form of import --- ``import *`` --- is used in a\nfunction and the function contains or is a nested block with free\nvariables, the compiler will raise a ``SyntaxError``.\n\nThe ``eval()`` and ``exec()`` functions do not have access to the full\nenvironment for resolving names. Names may be resolved in the local\nand global namespaces of the caller. Free variables are not resolved\nin the nearest enclosing namespace, but in the global namespace. [1]\nThe ``exec()`` and ``eval()`` functions have optional arguments to\noverride the global and local namespace. If only one namespace is\nspecified, it is used for both.\n\n\nExceptions\n==========\n\nExceptions are a means of breaking out of the normal flow of control\nof a code block in order to handle errors or other exceptional\nconditions. An exception is *raised* at the point where the error is\ndetected; it may be *handled* by the surrounding code block or by any\ncode block that directly or indirectly invoked the code block where\nthe error occurred.\n\nThe Python interpreter raises an exception when it detects a run-time\nerror (such as division by zero). A Python program can also\nexplicitly raise an exception with the ``raise`` statement. Exception\nhandlers are specified with the ``try`` ... ``except`` statement. The\n``finally`` clause of such a statement can be used to specify cleanup\ncode which does not handle the exception, but is executed whether an\nexception occurred or not in the preceding code.\n\nPython uses the "termination" model of error handling: an exception\nhandler can find out what happened and continue execution at an outer\nlevel, but it cannot repair the cause of the error and retry the\nfailing operation (except by re-entering the offending piece of code\nfrom the top).\n\nWhen an exception is not handled at all, the interpreter terminates\nexecution of the program, or returns to its interactive main loop. In\neither case, it prints a stack backtrace, except when the exception is\n``SystemExit``.\n\nExceptions are identified by class instances. The ``except`` clause\nis selected depending on the class of the instance: it must reference\nthe class of the instance or a base class thereof. The instance can\nbe received by the handler and can carry additional information about\nthe exceptional condition.\n\nNote: Exception messages are not part of the Python API. Their contents\n may change from one version of Python to the next without warning\n and should not be relied on by code which will run under multiple\n versions of the interpreter.\n\nSee also the description of the ``try`` statement in section *The try\nstatement* and ``raise`` statement in section *The raise statement*.\n\n-[ Footnotes ]-\n\n[1] This limitation occurs because the code that is executed by these\n operations is not available at the time the module is compiled.\n', 'exprlists': '\nExpression lists\n****************\n\n expression_list ::= expression ( "," expression )* [","]\n\nAn expression list containing at least one comma yields a tuple. The\nlength of the tuple is the number of expressions in the list. The\nexpressions are evaluated from left to right.\n\nThe trailing comma is required only to create a single tuple (a.k.a. a\n*singleton*); it is optional in all other cases. A single expression\nwithout a trailing comma doesn\'t create a tuple, but rather yields the\nvalue of that expression. (To create an empty tuple, use an empty pair\nof parentheses: ``()``.)\n', 'floating': '\nFloating point literals\n***********************\n\nFloating point literals are described by the following lexical\ndefinitions:\n\n floatnumber ::= pointfloat | exponentfloat\n pointfloat ::= [intpart] fraction | intpart "."\n exponentfloat ::= (intpart | pointfloat) exponent\n intpart ::= digit+\n fraction ::= "." digit+\n exponent ::= ("e" | "E") ["+" | "-"] digit+\n\nNote that the integer and exponent parts are always interpreted using\nradix 10. For example, ``077e010`` is legal, and denotes the same\nnumber as ``77e10``. The allowed range of floating point literals is\nimplementation-dependent. Some examples of floating point literals:\n\n 3.14 10. .001 1e100 3.14e-10 0e0\n\nNote that numeric literals do not include a sign; a phrase like ``-1``\nis actually an expression composed of the unary operator ``-`` and the\nliteral ``1``.\n', 'for': '\nThe ``for`` statement\n*********************\n\nThe ``for`` statement is used to iterate over the elements of a\nsequence (such as a string, tuple or list) or other iterable object:\n\n for_stmt ::= "for" target_list "in" expression_list ":" suite\n ["else" ":" suite]\n\nThe expression list is evaluated once; it should yield an iterable\nobject. An iterator is created for the result of the\n``expression_list``. The suite is then executed once for each item\nprovided by the iterator, in the order of ascending indices. Each\nitem in turn is assigned to the target list using the standard rules\nfor assignments (see *Assignment statements*), and then the suite is\nexecuted. When the items are exhausted (which is immediately when the\nsequence is empty or an iterator raises a ``StopIteration``\nexception), the suite in the ``else`` clause, if present, is executed,\nand the loop terminates.\n\nA ``break`` statement executed in the first suite terminates the loop\nwithout executing the ``else`` clause\'s suite. A ``continue``\nstatement executed in the first suite skips the rest of the suite and\ncontinues with the next item, or with the ``else`` clause if there was\nno next item.\n\nThe suite may assign to the variable(s) in the target list; this does\nnot affect the next item assigned to it.\n\nNames in the target list are not deleted when the loop is finished,\nbut if the sequence is empty, it will not have been assigned to at all\nby the loop. Hint: the built-in function ``range()`` returns an\niterator of integers suitable to emulate the effect of Pascal\'s ``for\ni := a to b do``; e.g., ``list(range(3))`` returns the list ``[0, 1,\n2]``.\n\nNote: There is a subtlety when the sequence is being modified by the loop\n (this can only occur for mutable sequences, i.e. lists). An\n internal counter is used to keep track of which item is used next,\n and this is incremented on each iteration. When this counter has\n reached the length of the sequence the loop terminates. This means\n that if the suite deletes the current (or a previous) item from the\n sequence, the next item will be skipped (since it gets the index of\n the current item which has already been treated). Likewise, if the\n suite inserts an item in the sequence before the current item, the\n current item will be treated again the next time through the loop.\n This can lead to nasty bugs that can be avoided by making a\n temporary copy using a slice of the whole sequence, e.g.,\n\n for x in a[:]:\n if x < 0: a.remove(x)\n', @@ -45,11 +45,11 @@ 'integers': '\nInteger literals\n****************\n\nInteger literals are described by the following lexical definitions:\n\n integer ::= decimalinteger | octinteger | hexinteger | bininteger\n decimalinteger ::= nonzerodigit digit* | "0"+\n nonzerodigit ::= "1"..."9"\n digit ::= "0"..."9"\n octinteger ::= "0" ("o" | "O") octdigit+\n hexinteger ::= "0" ("x" | "X") hexdigit+\n bininteger ::= "0" ("b" | "B") bindigit+\n octdigit ::= "0"..."7"\n hexdigit ::= digit | "a"..."f" | "A"..."F"\n bindigit ::= "0" | "1"\n\nThere is no limit for the length of integer literals apart from what\ncan be stored in available memory.\n\nNote that leading zeros in a non-zero decimal number are not allowed.\nThis is for disambiguation with C-style octal literals, which Python\nused before version 3.0.\n\nSome examples of integer literals:\n\n 7 2147483647 0o177 0b100110111\n 3 79228162514264337593543950336 0o377 0x100000000\n 79228162514264337593543950336 0xdeadbeef\n', 'lambda': '\nLambdas\n*******\n\n lambda_form ::= "lambda" [parameter_list]: expression\n lambda_form_nocond ::= "lambda" [parameter_list]: expression_nocond\n\nLambda forms (lambda expressions) have the same syntactic position as\nexpressions. They are a shorthand to create anonymous functions; the\nexpression ``lambda arguments: expression`` yields a function object.\nThe unnamed object behaves like a function object defined with\n\n def (arguments):\n return expression\n\nSee section *Function definitions* for the syntax of parameter lists.\nNote that functions created with lambda forms cannot contain\nstatements or annotations.\n', 'lists': '\nList displays\n*************\n\nA list display is a possibly empty series of expressions enclosed in\nsquare brackets:\n\n list_display ::= "[" [expression_list | comprehension] "]"\n\nA list display yields a new list object, the contents being specified\nby either a list of expressions or a comprehension. When a comma-\nseparated list of expressions is supplied, its elements are evaluated\nfrom left to right and placed into the list object in that order.\nWhen a comprehension is supplied, the list is constructed from the\nelements resulting from the comprehension.\n', - 'naming': "\nNaming and binding\n******************\n\n*Names* refer to objects. Names are introduced by name binding\noperations. Each occurrence of a name in the program text refers to\nthe *binding* of that name established in the innermost function block\ncontaining the use.\n\nA *block* is a piece of Python program text that is executed as a\nunit. The following are blocks: a module, a function body, and a class\ndefinition. Each command typed interactively is a block. A script\nfile (a file given as standard input to the interpreter or specified\non the interpreter command line the first argument) is a code block.\nA script command (a command specified on the interpreter command line\nwith the '**-c**' option) is a code block. The string argument passed\nto the built-in functions ``eval()`` and ``exec()`` is a code block.\n\nA code block is executed in an *execution frame*. A frame contains\nsome administrative information (used for debugging) and determines\nwhere and how execution continues after the code block's execution has\ncompleted.\n\nA *scope* defines the visibility of a name within a block. If a local\nvariable is defined in a block, its scope includes that block. If the\ndefinition occurs in a function block, the scope extends to any blocks\ncontained within the defining one, unless a contained block introduces\na different binding for the name. The scope of names defined in a\nclass block is limited to the class block; it does not extend to the\ncode blocks of methods -- this includes comprehensions and generator\nexpressions since they are implemented using a function scope. This\nmeans that the following will fail:\n\n class A:\n a = 42\n b = list(a + i for i in range(10))\n\nWhen a name is used in a code block, it is resolved using the nearest\nenclosing scope. The set of all such scopes visible to a code block\nis called the block's *environment*.\n\nIf a name is bound in a block, it is a local variable of that block,\nunless declared as ``nonlocal``. If a name is bound at the module\nlevel, it is a global variable. (The variables of the module code\nblock are local and global.) If a variable is used in a code block\nbut not defined there, it is a *free variable*.\n\nWhen a name is not found at all, a ``NameError`` exception is raised.\nIf the name refers to a local variable that has not been bound, a\n``UnboundLocalError`` exception is raised. ``UnboundLocalError`` is a\nsubclass of ``NameError``.\n\nThe following constructs bind names: formal parameters to functions,\n``import`` statements, class and function definitions (these bind the\nclass or function name in the defining block), and targets that are\nidentifiers if occurring in an assignment, ``for`` loop header, or\nafter ``as`` in a ``with`` statement or ``except`` clause. The\n``import`` statement of the form ``from ... import *`` binds all names\ndefined in the imported module, except those beginning with an\nunderscore. This form may only be used at the module level.\n\nA target occurring in a ``del`` statement is also considered bound for\nthis purpose (though the actual semantics are to unbind the name). It\nis illegal to unbind a name that is referenced by an enclosing scope;\nthe compiler will report a ``SyntaxError``.\n\nEach assignment or import statement occurs within a block defined by a\nclass or function definition or at the module level (the top-level\ncode block).\n\nIf a name binding operation occurs anywhere within a code block, all\nuses of the name within the block are treated as references to the\ncurrent block. This can lead to errors when a name is used within a\nblock before it is bound. This rule is subtle. Python lacks\ndeclarations and allows name binding operations to occur anywhere\nwithin a code block. The local variables of a code block can be\ndetermined by scanning the entire text of the block for name binding\noperations.\n\nIf the ``global`` statement occurs within a block, all uses of the\nname specified in the statement refer to the binding of that name in\nthe top-level namespace. Names are resolved in the top-level\nnamespace by searching the global namespace, i.e. the namespace of the\nmodule containing the code block, and the builtins namespace, the\nnamespace of the module ``builtins``. The global namespace is\nsearched first. If the name is not found there, the builtins\nnamespace is searched. The global statement must precede all uses of\nthe name.\n\nThe builtins namespace associated with the execution of a code block\nis actually found by looking up the name ``__builtins__`` in its\nglobal namespace; this should be a dictionary or a module (in the\nlatter case the module's dictionary is used). By default, when in the\n``__main__`` module, ``__builtins__`` is the built-in module\n``builtins``; when in any other module, ``__builtins__`` is an alias\nfor the dictionary of the ``builtins`` module itself.\n``__builtins__`` can be set to a user-created dictionary to create a\nweak form of restricted execution.\n\n**CPython implementation detail:** Users should not touch\n``__builtins__``; it is strictly an implementation detail. Users\nwanting to override values in the builtins namespace should ``import``\nthe ``builtins`` module and modify its attributes appropriately.\n\nThe namespace for a module is automatically created the first time a\nmodule is imported. The main module for a script is always called\n``__main__``.\n\nThe ``global`` statement has the same scope as a name binding\noperation in the same block. If the nearest enclosing scope for a\nfree variable contains a global statement, the free variable is\ntreated as a global.\n\nA class definition is an executable statement that may use and define\nnames. These references follow the normal rules for name resolution.\nThe namespace of the class definition becomes the attribute dictionary\nof the class. Names defined at the class scope are not visible in\nmethods.\n\n\nInteraction with dynamic features\n=================================\n\nThere are several cases where Python statements are illegal when used\nin conjunction with nested scopes that contain free variables.\n\nIf a variable is referenced in an enclosing scope, it is illegal to\ndelete the name. An error will be reported at compile time.\n\nIf the wild card form of import --- ``import *`` --- is used in a\nfunction and the function contains or is a nested block with free\nvariables, the compiler will raise a ``SyntaxError``.\n\nThe ``eval()`` and ``exec()`` functions do not have access to the full\nenvironment for resolving names. Names may be resolved in the local\nand global namespaces of the caller. Free variables are not resolved\nin the nearest enclosing namespace, but in the global namespace. [1]\nThe ``exec()`` and ``eval()`` functions have optional arguments to\noverride the global and local namespace. If only one namespace is\nspecified, it is used for both.\n", - 'nonlocal': '\nThe ``nonlocal`` statement\n**************************\n\n nonlocal_stmt ::= "nonlocal" identifier ("," identifier)*\n\nThe ``nonlocal`` statement causes the listed identifiers to refer to\npreviously bound variables in the nearest enclosing scope. This is\nimportant because the default behavior for binding is to search the\nlocal namespace first. The statement allows encapsulated code to\nrebind variables outside of the local scope besides the global\n(module) scope.\n\nNames listed in a ``nonlocal`` statement, unlike to those listed in a\n``global`` statement, must refer to pre-existing bindings in an\nenclosing scope (the scope in which a new binding should be created\ncannot be determined unambiguously).\n\nNames listed in a ``nonlocal`` statement must not collide with pre-\nexisting bindings in the local scope.\n\nSee also:\n\n **PEP 3104** - Access to Names in Outer Scopes\n The specification for the ``nonlocal`` statement.\n\n-[ Footnotes ]-\n\n[1] It may occur within an ``except`` or ``else`` clause. The\n restriction on occurring in the ``try`` clause is implementor\'s\n laziness and will eventually be lifted.\n', + 'naming': "\nNaming and binding\n******************\n\n*Names* refer to objects. Names are introduced by name binding\noperations. Each occurrence of a name in the program text refers to\nthe *binding* of that name established in the innermost function block\ncontaining the use.\n\nA *block* is a piece of Python program text that is executed as a\nunit. The following are blocks: a module, a function body, and a class\ndefinition. Each command typed interactively is a block. A script\nfile (a file given as standard input to the interpreter or specified\non the interpreter command line the first argument) is a code block.\nA script command (a command specified on the interpreter command line\nwith the '**-c**' option) is a code block. The string argument passed\nto the built-in functions ``eval()`` and ``exec()`` is a code block.\n\nA code block is executed in an *execution frame*. A frame contains\nsome administrative information (used for debugging) and determines\nwhere and how execution continues after the code block's execution has\ncompleted.\n\nA *scope* defines the visibility of a name within a block. If a local\nvariable is defined in a block, its scope includes that block. If the\ndefinition occurs in a function block, the scope extends to any blocks\ncontained within the defining one, unless a contained block introduces\na different binding for the name. The scope of names defined in a\nclass block is limited to the class block; it does not extend to the\ncode blocks of methods -- this includes comprehensions and generator\nexpressions since they are implemented using a function scope. This\nmeans that the following will fail:\n\n class A:\n a = 42\n b = list(a + i for i in range(10))\n\nWhen a name is used in a code block, it is resolved using the nearest\nenclosing scope. The set of all such scopes visible to a code block\nis called the block's *environment*.\n\nIf a name is bound in a block, it is a local variable of that block,\nunless declared as ``nonlocal``. If a name is bound at the module\nlevel, it is a global variable. (The variables of the module code\nblock are local and global.) If a variable is used in a code block\nbut not defined there, it is a *free variable*.\n\nWhen a name is not found at all, a ``NameError`` exception is raised.\nIf the name refers to a local variable that has not been bound, a\n``UnboundLocalError`` exception is raised. ``UnboundLocalError`` is a\nsubclass of ``NameError``.\n\nThe following constructs bind names: formal parameters to functions,\n``import`` statements, class and function definitions (these bind the\nclass or function name in the defining block), and targets that are\nidentifiers if occurring in an assignment, ``for`` loop header, or\nafter ``as`` in a ``with`` statement or ``except`` clause. The\n``import`` statement of the form ``from ... import *`` binds all names\ndefined in the imported module, except those beginning with an\nunderscore. This form may only be used at the module level.\n\nA target occurring in a ``del`` statement is also considered bound for\nthis purpose (though the actual semantics are to unbind the name).\n\nEach assignment or import statement occurs within a block defined by a\nclass or function definition or at the module level (the top-level\ncode block).\n\nIf a name binding operation occurs anywhere within a code block, all\nuses of the name within the block are treated as references to the\ncurrent block. This can lead to errors when a name is used within a\nblock before it is bound. This rule is subtle. Python lacks\ndeclarations and allows name binding operations to occur anywhere\nwithin a code block. The local variables of a code block can be\ndetermined by scanning the entire text of the block for name binding\noperations.\n\nIf the ``global`` statement occurs within a block, all uses of the\nname specified in the statement refer to the binding of that name in\nthe top-level namespace. Names are resolved in the top-level\nnamespace by searching the global namespace, i.e. the namespace of the\nmodule containing the code block, and the builtins namespace, the\nnamespace of the module ``builtins``. The global namespace is\nsearched first. If the name is not found there, the builtins\nnamespace is searched. The global statement must precede all uses of\nthe name.\n\nThe builtins namespace associated with the execution of a code block\nis actually found by looking up the name ``__builtins__`` in its\nglobal namespace; this should be a dictionary or a module (in the\nlatter case the module's dictionary is used). By default, when in the\n``__main__`` module, ``__builtins__`` is the built-in module\n``builtins``; when in any other module, ``__builtins__`` is an alias\nfor the dictionary of the ``builtins`` module itself.\n``__builtins__`` can be set to a user-created dictionary to create a\nweak form of restricted execution.\n\n**CPython implementation detail:** Users should not touch\n``__builtins__``; it is strictly an implementation detail. Users\nwanting to override values in the builtins namespace should ``import``\nthe ``builtins`` module and modify its attributes appropriately.\n\nThe namespace for a module is automatically created the first time a\nmodule is imported. The main module for a script is always called\n``__main__``.\n\nThe ``global`` statement has the same scope as a name binding\noperation in the same block. If the nearest enclosing scope for a\nfree variable contains a global statement, the free variable is\ntreated as a global.\n\nA class definition is an executable statement that may use and define\nnames. These references follow the normal rules for name resolution.\nThe namespace of the class definition becomes the attribute dictionary\nof the class. Names defined at the class scope are not visible in\nmethods.\n\n\nInteraction with dynamic features\n=================================\n\nThere are several cases where Python statements are illegal when used\nin conjunction with nested scopes that contain free variables.\n\nIf a variable is referenced in an enclosing scope, it is illegal to\ndelete the name. An error will be reported at compile time.\n\nIf the wild card form of import --- ``import *`` --- is used in a\nfunction and the function contains or is a nested block with free\nvariables, the compiler will raise a ``SyntaxError``.\n\nThe ``eval()`` and ``exec()`` functions do not have access to the full\nenvironment for resolving names. Names may be resolved in the local\nand global namespaces of the caller. Free variables are not resolved\nin the nearest enclosing namespace, but in the global namespace. [1]\nThe ``exec()`` and ``eval()`` functions have optional arguments to\noverride the global and local namespace. If only one namespace is\nspecified, it is used for both.\n", + 'nonlocal': '\nThe ``nonlocal`` statement\n**************************\n\n nonlocal_stmt ::= "nonlocal" identifier ("," identifier)*\n\nThe ``nonlocal`` statement causes the listed identifiers to refer to\npreviously bound variables in the nearest enclosing scope. This is\nimportant because the default behavior for binding is to search the\nlocal namespace first. The statement allows encapsulated code to\nrebind variables outside of the local scope besides the global\n(module) scope.\n\nNames listed in a ``nonlocal`` statement, unlike to those listed in a\n``global`` statement, must refer to pre-existing bindings in an\nenclosing scope (the scope in which a new binding should be created\ncannot be determined unambiguously).\n\nNames listed in a ``nonlocal`` statement must not collide with pre-\nexisting bindings in the local scope.\n\nSee also:\n\n **PEP 3104** - Access to Names in Outer Scopes\n The specification for the ``nonlocal`` statement.\n', 'numbers': "\nNumeric literals\n****************\n\nThere are three types of numeric literals: integers, floating point\nnumbers, and imaginary numbers. There are no complex literals\n(complex numbers can be formed by adding a real number and an\nimaginary number).\n\nNote that numeric literals do not include a sign; a phrase like ``-1``\nis actually an expression composed of the unary operator '``-``' and\nthe literal ``1``.\n", 'numeric-types': "\nEmulating numeric types\n***********************\n\nThe following methods can be defined to emulate numeric objects.\nMethods corresponding to operations that are not supported by the\nparticular kind of number implemented (e.g., bitwise operations for\nnon-integral numbers) should be left undefined.\n\nobject.__add__(self, other)\nobject.__sub__(self, other)\nobject.__mul__(self, other)\nobject.__truediv__(self, other)\nobject.__floordiv__(self, other)\nobject.__mod__(self, other)\nobject.__divmod__(self, other)\nobject.__pow__(self, other[, modulo])\nobject.__lshift__(self, other)\nobject.__rshift__(self, other)\nobject.__and__(self, other)\nobject.__xor__(self, other)\nobject.__or__(self, other)\n\n These methods are called to implement the binary arithmetic\n operations (``+``, ``-``, ``*``, ``/``, ``//``, ``%``,\n ``divmod()``, ``pow()``, ``**``, ``<<``, ``>>``, ``&``, ``^``,\n ``|``). For instance, to evaluate the expression ``x + y``, where\n *x* is an instance of a class that has an ``__add__()`` method,\n ``x.__add__(y)`` is called. The ``__divmod__()`` method should be\n the equivalent to using ``__floordiv__()`` and ``__mod__()``; it\n should not be related to ``__truediv__()``. Note that\n ``__pow__()`` should be defined to accept an optional third\n argument if the ternary version of the built-in ``pow()`` function\n is to be supported.\n\n If one of those methods does not support the operation with the\n supplied arguments, it should return ``NotImplemented``.\n\nobject.__radd__(self, other)\nobject.__rsub__(self, other)\nobject.__rmul__(self, other)\nobject.__rtruediv__(self, other)\nobject.__rfloordiv__(self, other)\nobject.__rmod__(self, other)\nobject.__rdivmod__(self, other)\nobject.__rpow__(self, other)\nobject.__rlshift__(self, other)\nobject.__rrshift__(self, other)\nobject.__rand__(self, other)\nobject.__rxor__(self, other)\nobject.__ror__(self, other)\n\n These methods are called to implement the binary arithmetic\n operations (``+``, ``-``, ``*``, ``/``, ``//``, ``%``,\n ``divmod()``, ``pow()``, ``**``, ``<<``, ``>>``, ``&``, ``^``,\n ``|``) with reflected (swapped) operands. These functions are only\n called if the left operand does not support the corresponding\n operation and the operands are of different types. [2] For\n instance, to evaluate the expression ``x - y``, where *y* is an\n instance of a class that has an ``__rsub__()`` method,\n ``y.__rsub__(x)`` is called if ``x.__sub__(y)`` returns\n *NotImplemented*.\n\n Note that ternary ``pow()`` will not try calling ``__rpow__()``\n (the coercion rules would become too complicated).\n\n Note: If the right operand's type is a subclass of the left operand's\n type and that subclass provides the reflected method for the\n operation, this method will be called before the left operand's\n non-reflected method. This behavior allows subclasses to\n override their ancestors' operations.\n\nobject.__iadd__(self, other)\nobject.__isub__(self, other)\nobject.__imul__(self, other)\nobject.__itruediv__(self, other)\nobject.__ifloordiv__(self, other)\nobject.__imod__(self, other)\nobject.__ipow__(self, other[, modulo])\nobject.__ilshift__(self, other)\nobject.__irshift__(self, other)\nobject.__iand__(self, other)\nobject.__ixor__(self, other)\nobject.__ior__(self, other)\n\n These methods are called to implement the augmented arithmetic\n assignments (``+=``, ``-=``, ``*=``, ``/=``, ``//=``, ``%=``,\n ``**=``, ``<<=``, ``>>=``, ``&=``, ``^=``, ``|=``). These methods\n should attempt to do the operation in-place (modifying *self*) and\n return the result (which could be, but does not have to be,\n *self*). If a specific method is not defined, the augmented\n assignment falls back to the normal methods. For instance, to\n execute the statement ``x += y``, where *x* is an instance of a\n class that has an ``__iadd__()`` method, ``x.__iadd__(y)`` is\n called. If *x* is an instance of a class that does not define a\n ``__iadd__()`` method, ``x.__add__(y)`` and ``y.__radd__(x)`` are\n considered, as with the evaluation of ``x + y``.\n\nobject.__neg__(self)\nobject.__pos__(self)\nobject.__abs__(self)\nobject.__invert__(self)\n\n Called to implement the unary arithmetic operations (``-``, ``+``,\n ``abs()`` and ``~``).\n\nobject.__complex__(self)\nobject.__int__(self)\nobject.__float__(self)\nobject.__round__(self[, n])\n\n Called to implement the built-in functions ``complex()``,\n ``int()``, ``float()`` and ``round()``. Should return a value of\n the appropriate type.\n\nobject.__index__(self)\n\n Called to implement ``operator.index()``. Also called whenever\n Python needs an integer object (such as in slicing, or in the\n built-in ``bin()``, ``hex()`` and ``oct()`` functions). Must return\n an integer.\n", - 'objects': '\nObjects, values and types\n*************************\n\n*Objects* are Python\'s abstraction for data. All data in a Python\nprogram is represented by objects or by relations between objects. (In\na sense, and in conformance to Von Neumann\'s model of a "stored\nprogram computer," code is also represented by objects.)\n\nEvery object has an identity, a type and a value. An object\'s\n*identity* never changes once it has been created; you may think of it\nas the object\'s address in memory. The \'``is``\' operator compares the\nidentity of two objects; the ``id()`` function returns an integer\nrepresenting its identity (currently implemented as its address). An\nobject\'s *type* is also unchangeable. [1] An object\'s type determines\nthe operations that the object supports (e.g., "does it have a\nlength?") and also defines the possible values for objects of that\ntype. The ``type()`` function returns an object\'s type (which is an\nobject itself). The *value* of some objects can change. Objects\nwhose value can change are said to be *mutable*; objects whose value\nis unchangeable once they are created are called *immutable*. (The\nvalue of an immutable container object that contains a reference to a\nmutable object can change when the latter\'s value is changed; however\nthe container is still considered immutable, because the collection of\nobjects it contains cannot be changed. So, immutability is not\nstrictly the same as having an unchangeable value, it is more subtle.)\nAn object\'s mutability is determined by its type; for instance,\nnumbers, strings and tuples are immutable, while dictionaries and\nlists are mutable.\n\nObjects are never explicitly destroyed; however, when they become\nunreachable they may be garbage-collected. An implementation is\nallowed to postpone garbage collection or omit it altogether --- it is\na matter of implementation quality how garbage collection is\nimplemented, as long as no objects are collected that are still\nreachable.\n\n**CPython implementation detail:** CPython currently uses a reference-\ncounting scheme with (optional) delayed detection of cyclically linked\ngarbage, which collects most objects as soon as they become\nunreachable, but is not guaranteed to collect garbage containing\ncircular references. See the documentation of the ``gc`` module for\ninformation on controlling the collection of cyclic garbage. Other\nimplementations act differently and CPython may change.\n\nNote that the use of the implementation\'s tracing or debugging\nfacilities may keep objects alive that would normally be collectable.\nAlso note that catching an exception with a \'``try``...``except``\'\nstatement may keep objects alive.\n\nSome objects contain references to "external" resources such as open\nfiles or windows. It is understood that these resources are freed\nwhen the object is garbage-collected, but since garbage collection is\nnot guaranteed to happen, such objects also provide an explicit way to\nrelease the external resource, usually a ``close()`` method. Programs\nare strongly recommended to explicitly close such objects. The\n\'``try``...``finally``\' statement and the \'``with``\' statement provide\nconvenient ways to do this.\n\nSome objects contain references to other objects; these are called\n*containers*. Examples of containers are tuples, lists and\ndictionaries. The references are part of a container\'s value. In\nmost cases, when we talk about the value of a container, we imply the\nvalues, not the identities of the contained objects; however, when we\ntalk about the mutability of a container, only the identities of the\nimmediately contained objects are implied. So, if an immutable\ncontainer (like a tuple) contains a reference to a mutable object, its\nvalue changes if that mutable object is changed.\n\nTypes affect almost all aspects of object behavior. Even the\nimportance of object identity is affected in some sense: for immutable\ntypes, operations that compute new values may actually return a\nreference to any existing object with the same type and value, while\nfor mutable objects this is not allowed. E.g., after ``a = 1; b =\n1``, ``a`` and ``b`` may or may not refer to the same object with the\nvalue one, depending on the implementation, but after ``c = []; d =\n[]``, ``c`` and ``d`` are guaranteed to refer to two different,\nunique, newly created empty lists. (Note that ``c = d = []`` assigns\nthe same object to both ``c`` and ``d``.)\n', + 'objects': '\nObjects, values and types\n*************************\n\n*Objects* are Python\'s abstraction for data. All data in a Python\nprogram is represented by objects or by relations between objects. (In\na sense, and in conformance to Von Neumann\'s model of a "stored\nprogram computer," code is also represented by objects.)\n\nEvery object has an identity, a type and a value. An object\'s\n*identity* never changes once it has been created; you may think of it\nas the object\'s address in memory. The \'``is``\' operator compares the\nidentity of two objects; the ``id()`` function returns an integer\nrepresenting its identity (currently implemented as its address). An\nobject\'s *type* is also unchangeable. [1] An object\'s type determines\nthe operations that the object supports (e.g., "does it have a\nlength?") and also defines the possible values for objects of that\ntype. The ``type()`` function returns an object\'s type (which is an\nobject itself). The *value* of some objects can change. Objects\nwhose value can change are said to be *mutable*; objects whose value\nis unchangeable once they are created are called *immutable*. (The\nvalue of an immutable container object that contains a reference to a\nmutable object can change when the latter\'s value is changed; however\nthe container is still considered immutable, because the collection of\nobjects it contains cannot be changed. So, immutability is not\nstrictly the same as having an unchangeable value, it is more subtle.)\nAn object\'s mutability is determined by its type; for instance,\nnumbers, strings and tuples are immutable, while dictionaries and\nlists are mutable.\n\nObjects are never explicitly destroyed; however, when they become\nunreachable they may be garbage-collected. An implementation is\nallowed to postpone garbage collection or omit it altogether --- it is\na matter of implementation quality how garbage collection is\nimplemented, as long as no objects are collected that are still\nreachable.\n\n**CPython implementation detail:** CPython currently uses a reference-\ncounting scheme with (optional) delayed detection of cyclically linked\ngarbage, which collects most objects as soon as they become\nunreachable, but is not guaranteed to collect garbage containing\ncircular references. See the documentation of the ``gc`` module for\ninformation on controlling the collection of cyclic garbage. Other\nimplementations act differently and CPython may change. Do not depend\non immediate finalization of objects when they become unreachable (ex:\nalways close files).\n\nNote that the use of the implementation\'s tracing or debugging\nfacilities may keep objects alive that would normally be collectable.\nAlso note that catching an exception with a \'``try``...``except``\'\nstatement may keep objects alive.\n\nSome objects contain references to "external" resources such as open\nfiles or windows. It is understood that these resources are freed\nwhen the object is garbage-collected, but since garbage collection is\nnot guaranteed to happen, such objects also provide an explicit way to\nrelease the external resource, usually a ``close()`` method. Programs\nare strongly recommended to explicitly close such objects. The\n\'``try``...``finally``\' statement and the \'``with``\' statement provide\nconvenient ways to do this.\n\nSome objects contain references to other objects; these are called\n*containers*. Examples of containers are tuples, lists and\ndictionaries. The references are part of a container\'s value. In\nmost cases, when we talk about the value of a container, we imply the\nvalues, not the identities of the contained objects; however, when we\ntalk about the mutability of a container, only the identities of the\nimmediately contained objects are implied. So, if an immutable\ncontainer (like a tuple) contains a reference to a mutable object, its\nvalue changes if that mutable object is changed.\n\nTypes affect almost all aspects of object behavior. Even the\nimportance of object identity is affected in some sense: for immutable\ntypes, operations that compute new values may actually return a\nreference to any existing object with the same type and value, while\nfor mutable objects this is not allowed. E.g., after ``a = 1; b =\n1``, ``a`` and ``b`` may or may not refer to the same object with the\nvalue one, depending on the implementation, but after ``c = []; d =\n[]``, ``c`` and ``d`` are guaranteed to refer to two different,\nunique, newly created empty lists. (Note that ``c = d = []`` assigns\nthe same object to both ``c`` and ``d``.)\n', 'operator-summary': '\nSummary\n*******\n\nThe following table summarizes the operator precedences in Python,\nfrom lowest precedence (least binding) to highest precedence (most\nbinding). Operators in the same box have the same precedence. Unless\nthe syntax is explicitly given, operators are binary. Operators in\nthe same box group left to right (except for comparisons, including\ntests, which all have the same precedence and chain from left to right\n--- see section *Comparisons* --- and exponentiation, which groups\nfrom right to left).\n\n+-------------------------------------------------+---------------------------------------+\n| Operator | Description |\n+=================================================+=======================================+\n| ``lambda`` | Lambda expression |\n+-------------------------------------------------+---------------------------------------+\n| ``if`` -- ``else`` | Conditional expression |\n+-------------------------------------------------+---------------------------------------+\n| ``or`` | Boolean OR |\n+-------------------------------------------------+---------------------------------------+\n| ``and`` | Boolean AND |\n+-------------------------------------------------+---------------------------------------+\n| ``not`` *x* | Boolean NOT |\n+-------------------------------------------------+---------------------------------------+\n| ``in``, ``not`` ``in``, ``is``, ``is not``, | Comparisons, including membership |\n| ``<``, ``<=``, ``>``, ``>=``, ``!=``, ``==`` | tests and identity tests, |\n+-------------------------------------------------+---------------------------------------+\n| ``|`` | Bitwise OR |\n+-------------------------------------------------+---------------------------------------+\n| ``^`` | Bitwise XOR |\n+-------------------------------------------------+---------------------------------------+\n| ``&`` | Bitwise AND |\n+-------------------------------------------------+---------------------------------------+\n| ``<<``, ``>>`` | Shifts |\n+-------------------------------------------------+---------------------------------------+\n| ``+``, ``-`` | Addition and subtraction |\n+-------------------------------------------------+---------------------------------------+\n| ``*``, ``/``, ``//``, ``%`` | Multiplication, division, remainder |\n| | [5] |\n+-------------------------------------------------+---------------------------------------+\n| ``+x``, ``-x``, ``~x`` | Positive, negative, bitwise NOT |\n+-------------------------------------------------+---------------------------------------+\n| ``**`` | Exponentiation [6] |\n+-------------------------------------------------+---------------------------------------+\n| ``x[index]``, ``x[index:index]``, | Subscription, slicing, call, |\n| ``x(arguments...)``, ``x.attribute`` | attribute reference |\n+-------------------------------------------------+---------------------------------------+\n| ``(expressions...)``, ``[expressions...]``, | Binding or tuple display, list |\n| ``{key:datum...}``, ``{expressions...}`` | display, dictionary display, set |\n| | display |\n+-------------------------------------------------+---------------------------------------+\n\n-[ Footnotes ]-\n\n[1] While ``abs(x%y) < abs(y)`` is true mathematically, for floats it\n may not be true numerically due to roundoff. For example, and\n assuming a platform on which a Python float is an IEEE 754 double-\n precision number, in order that ``-1e-100 % 1e100`` have the same\n sign as ``1e100``, the computed result is ``-1e-100 + 1e100``,\n which is numerically exactly equal to ``1e100``. The function\n ``math.fmod()`` returns a result whose sign matches the sign of\n the first argument instead, and so returns ``-1e-100`` in this\n case. Which approach is more appropriate depends on the\n application.\n\n[2] If x is very close to an exact integer multiple of y, it\'s\n possible for ``x//y`` to be one larger than ``(x-x%y)//y`` due to\n rounding. In such cases, Python returns the latter result, in\n order to preserve that ``divmod(x,y)[0] * y + x % y`` be very\n close to ``x``.\n\n[3] While comparisons between strings make sense at the byte level,\n they may be counter-intuitive to users. For example, the strings\n ``"\\u00C7"`` and ``"\\u0327\\u0043"`` compare differently, even\n though they both represent the same unicode character (LATIN\n CAPITAL LETTER C WITH CEDILLA). To compare strings in a human\n recognizable way, compare using ``unicodedata.normalize()``.\n\n[4] Due to automatic garbage-collection, free lists, and the dynamic\n nature of descriptors, you may notice seemingly unusual behaviour\n in certain uses of the ``is`` operator, like those involving\n comparisons between instance methods, or constants. Check their\n documentation for more info.\n\n[5] The ``%`` operator is also used for string formatting; the same\n precedence applies.\n\n[6] The power operator ``**`` binds less tightly than an arithmetic or\n bitwise unary operator on its right, that is, ``2**-1`` is\n ``0.5``.\n', 'pass': '\nThe ``pass`` statement\n**********************\n\n pass_stmt ::= "pass"\n\n``pass`` is a null operation --- when it is executed, nothing happens.\nIt is useful as a placeholder when a statement is required\nsyntactically, but no code needs to be executed, for example:\n\n def f(arg): pass # a function that does nothing (yet)\n\n class C: pass # a class with no methods (yet)\n', 'power': '\nThe power operator\n******************\n\nThe power operator binds more tightly than unary operators on its\nleft; it binds less tightly than unary operators on its right. The\nsyntax is:\n\n power ::= primary ["**" u_expr]\n\nThus, in an unparenthesized sequence of power and unary operators, the\noperators are evaluated from right to left (this does not constrain\nthe evaluation order for the operands): ``-1**2`` results in ``-1``.\n\nThe power operator has the same semantics as the built-in ``pow()``\nfunction, when called with two arguments: it yields its left argument\nraised to the power of its right argument. The numeric arguments are\nfirst converted to a common type, and the result is of that type.\n\nFor int operands, the result has the same type as the operands unless\nthe second argument is negative; in that case, all arguments are\nconverted to float and a float result is delivered. For example,\n``10**2`` returns ``100``, but ``10**-2`` returns ``0.01``.\n\nRaising ``0.0`` to a negative power results in a\n``ZeroDivisionError``. Raising a negative number to a fractional power\nresults in a ``complex`` number. (In earlier versions it raised a\n``ValueError``.)\n', @@ -59,7 +59,7 @@ 'shifting': '\nShifting operations\n*******************\n\nThe shifting operations have lower priority than the arithmetic\noperations:\n\n shift_expr ::= a_expr | shift_expr ( "<<" | ">>" ) a_expr\n\nThese operators accept integers as arguments. They shift the first\nargument to the left or right by the number of bits given by the\nsecond argument.\n\nA right shift by *n* bits is defined as division by ``pow(2,n)``. A\nleft shift by *n* bits is defined as multiplication with ``pow(2,n)``.\n\nNote: In the current implementation, the right-hand operand is required to\n be at most ``sys.maxsize``. If the right-hand operand is larger\n than ``sys.maxsize`` an ``OverflowError`` exception is raised.\n', 'slicings': '\nSlicings\n********\n\nA slicing selects a range of items in a sequence object (e.g., a\nstring, tuple or list). Slicings may be used as expressions or as\ntargets in assignment or ``del`` statements. The syntax for a\nslicing:\n\n slicing ::= primary "[" slice_list "]"\n slice_list ::= slice_item ("," slice_item)* [","]\n slice_item ::= expression | proper_slice\n proper_slice ::= [lower_bound] ":" [upper_bound] [ ":" [stride] ]\n lower_bound ::= expression\n upper_bound ::= expression\n stride ::= expression\n\nThere is ambiguity in the formal syntax here: anything that looks like\nan expression list also looks like a slice list, so any subscription\ncan be interpreted as a slicing. Rather than further complicating the\nsyntax, this is disambiguated by defining that in this case the\ninterpretation as a subscription takes priority over the\ninterpretation as a slicing (this is the case if the slice list\ncontains no proper slice).\n\nThe semantics for a slicing are as follows. The primary must evaluate\nto a mapping object, and it is indexed (using the same\n``__getitem__()`` method as normal subscription) with a key that is\nconstructed from the slice list, as follows. If the slice list\ncontains at least one comma, the key is a tuple containing the\nconversion of the slice items; otherwise, the conversion of the lone\nslice item is the key. The conversion of a slice item that is an\nexpression is that expression. The conversion of a proper slice is a\nslice object (see section *The standard type hierarchy*) whose\n``start``, ``stop`` and ``step`` attributes are the values of the\nexpressions given as lower bound, upper bound and stride,\nrespectively, substituting ``None`` for missing expressions.\n', 'specialattrs': "\nSpecial Attributes\n******************\n\nThe implementation adds a few special read-only attributes to several\nobject types, where they are relevant. Some of these are not reported\nby the ``dir()`` built-in function.\n\nobject.__dict__\n\n A dictionary or other mapping object used to store an object's\n (writable) attributes.\n\ninstance.__class__\n\n The class to which a class instance belongs.\n\nclass.__bases__\n\n The tuple of base classes of a class object.\n\nclass.__name__\n\n The name of the class or type.\n\nThe following attributes are only supported by *new-style class*es.\n\nclass.__mro__\n\n This attribute is a tuple of classes that are considered when\n looking for base classes during method resolution.\n\nclass.mro()\n\n This method can be overridden by a metaclass to customize the\n method resolution order for its instances. It is called at class\n instantiation, and its result is stored in ``__mro__``.\n\nclass.__subclasses__()\n\n Each new-style class keeps a list of weak references to its\n immediate subclasses. This method returns a list of all those\n references still alive. Example:\n\n >>> int.__subclasses__()\n []\n\n-[ Footnotes ]-\n\n[1] Additional information on these special methods may be found in\n the Python Reference Manual (*Basic customization*).\n\n[2] As a consequence, the list ``[1, 2]`` is considered equal to\n ``[1.0, 2.0]``, and similarly for tuples.\n\n[3] They must have since the parser can't tell the type of the\n operands.\n\n[4] To format only a tuple you should therefore provide a singleton\n tuple whose only element is the tuple to be formatted.\n", - 'specialnames': '\nSpecial method names\n********************\n\nA class can implement certain operations that are invoked by special\nsyntax (such as arithmetic operations or subscripting and slicing) by\ndefining methods with special names. This is Python\'s approach to\n*operator overloading*, allowing classes to define their own behavior\nwith respect to language operators. For instance, if a class defines\na method named ``__getitem__()``, and ``x`` is an instance of this\nclass, then ``x[i]`` is roughly equivalent to ``type(x).__getitem__(x,\ni)``. Except where mentioned, attempts to execute an operation raise\nan exception when no appropriate method is defined (typically\n``AttributeError`` or ``TypeError``).\n\nWhen implementing a class that emulates any built-in type, it is\nimportant that the emulation only be implemented to the degree that it\nmakes sense for the object being modelled. For example, some\nsequences may work well with retrieval of individual elements, but\nextracting a slice may not make sense. (One example of this is the\n``NodeList`` interface in the W3C\'s Document Object Model.)\n\n\nBasic customization\n===================\n\nobject.__new__(cls[, ...])\n\n Called to create a new instance of class *cls*. ``__new__()`` is a\n static method (special-cased so you need not declare it as such)\n that takes the class of which an instance was requested as its\n first argument. The remaining arguments are those passed to the\n object constructor expression (the call to the class). The return\n value of ``__new__()`` should be the new object instance (usually\n an instance of *cls*).\n\n Typical implementations create a new instance of the class by\n invoking the superclass\'s ``__new__()`` method using\n ``super(currentclass, cls).__new__(cls[, ...])`` with appropriate\n arguments and then modifying the newly-created instance as\n necessary before returning it.\n\n If ``__new__()`` returns an instance of *cls*, then the new\n instance\'s ``__init__()`` method will be invoked like\n ``__init__(self[, ...])``, where *self* is the new instance and the\n remaining arguments are the same as were passed to ``__new__()``.\n\n If ``__new__()`` does not return an instance of *cls*, then the new\n instance\'s ``__init__()`` method will not be invoked.\n\n ``__new__()`` is intended mainly to allow subclasses of immutable\n types (like int, str, or tuple) to customize instance creation. It\n is also commonly overridden in custom metaclasses in order to\n customize class creation.\n\nobject.__init__(self[, ...])\n\n Called when the instance is created. The arguments are those\n passed to the class constructor expression. If a base class has an\n ``__init__()`` method, the derived class\'s ``__init__()`` method,\n if any, must explicitly call it to ensure proper initialization of\n the base class part of the instance; for example:\n ``BaseClass.__init__(self, [args...])``. As a special constraint\n on constructors, no value may be returned; doing so will cause a\n ``TypeError`` to be raised at runtime.\n\nobject.__del__(self)\n\n Called when the instance is about to be destroyed. This is also\n called a destructor. If a base class has a ``__del__()`` method,\n the derived class\'s ``__del__()`` method, if any, must explicitly\n call it to ensure proper deletion of the base class part of the\n instance. Note that it is possible (though not recommended!) for\n the ``__del__()`` method to postpone destruction of the instance by\n creating a new reference to it. It may then be called at a later\n time when this new reference is deleted. It is not guaranteed that\n ``__del__()`` methods are called for objects that still exist when\n the interpreter exits.\n\n Note: ``del x`` doesn\'t directly call ``x.__del__()`` --- the former\n decrements the reference count for ``x`` by one, and the latter\n is only called when ``x``\'s reference count reaches zero. Some\n common situations that may prevent the reference count of an\n object from going to zero include: circular references between\n objects (e.g., a doubly-linked list or a tree data structure with\n parent and child pointers); a reference to the object on the\n stack frame of a function that caught an exception (the traceback\n stored in ``sys.exc_info()[2]`` keeps the stack frame alive); or\n a reference to the object on the stack frame that raised an\n unhandled exception in interactive mode (the traceback stored in\n ``sys.last_traceback`` keeps the stack frame alive). The first\n situation can only be remedied by explicitly breaking the cycles;\n the latter two situations can be resolved by storing ``None`` in\n ``sys.last_traceback``. Circular references which are garbage are\n detected when the option cycle detector is enabled (it\'s on by\n default), but can only be cleaned up if there are no Python-\n level ``__del__()`` methods involved. Refer to the documentation\n for the ``gc`` module for more information about how\n ``__del__()`` methods are handled by the cycle detector,\n particularly the description of the ``garbage`` value.\n\n Warning: Due to the precarious circumstances under which ``__del__()``\n methods are invoked, exceptions that occur during their execution\n are ignored, and a warning is printed to ``sys.stderr`` instead.\n Also, when ``__del__()`` is invoked in response to a module being\n deleted (e.g., when execution of the program is done), other\n globals referenced by the ``__del__()`` method may already have\n been deleted or in the process of being torn down (e.g. the\n import machinery shutting down). For this reason, ``__del__()``\n methods should do the absolute minimum needed to maintain\n external invariants. Starting with version 1.5, Python\n guarantees that globals whose name begins with a single\n underscore are deleted from their module before other globals are\n deleted; if no other references to such globals exist, this may\n help in assuring that imported modules are still available at the\n time when the ``__del__()`` method is called.\n\nobject.__repr__(self)\n\n Called by the ``repr()`` built-in function to compute the\n "official" string representation of an object. If at all possible,\n this should look like a valid Python expression that could be used\n to recreate an object with the same value (given an appropriate\n environment). If this is not possible, a string of the form\n ``<...some useful description...>`` should be returned. The return\n value must be a string object. If a class defines ``__repr__()``\n but not ``__str__()``, then ``__repr__()`` is also used when an\n "informal" string representation of instances of that class is\n required.\n\n This is typically used for debugging, so it is important that the\n representation is information-rich and unambiguous.\n\nobject.__str__(self)\n\n Called by the ``str()`` built-in function and by the ``print()``\n function to compute the "informal" string representation of an\n object. This differs from ``__repr__()`` in that it does not have\n to be a valid Python expression: a more convenient or concise\n representation may be used instead. The return value must be a\n string object.\n\nobject.__format__(self, format_spec)\n\n Called by the ``format()`` built-in function (and by extension, the\n ``format()`` method of class ``str``) to produce a "formatted"\n string representation of an object. The ``format_spec`` argument is\n a string that contains a description of the formatting options\n desired. The interpretation of the ``format_spec`` argument is up\n to the type implementing ``__format__()``, however most classes\n will either delegate formatting to one of the built-in types, or\n use a similar formatting option syntax.\n\n See *Format Specification Mini-Language* for a description of the\n standard formatting syntax.\n\n The return value must be a string object.\n\nobject.__lt__(self, other)\nobject.__le__(self, other)\nobject.__eq__(self, other)\nobject.__ne__(self, other)\nobject.__gt__(self, other)\nobject.__ge__(self, other)\n\n These are the so-called "rich comparison" methods. The\n correspondence between operator symbols and method names is as\n follows: ``xy`` calls ``x.__gt__(y)``, and ``x>=y`` calls\n ``x.__ge__(y)``.\n\n A rich comparison method may return the singleton\n ``NotImplemented`` if it does not implement the operation for a\n given pair of arguments. By convention, ``False`` and ``True`` are\n returned for a successful comparison. However, these methods can\n return any value, so if the comparison operator is used in a\n Boolean context (e.g., in the condition of an ``if`` statement),\n Python will call ``bool()`` on the value to determine if the result\n is true or false.\n\n There are no implied relationships among the comparison operators.\n The truth of ``x==y`` does not imply that ``x!=y`` is false.\n Accordingly, when defining ``__eq__()``, one should also define\n ``__ne__()`` so that the operators will behave as expected. See\n the paragraph on ``__hash__()`` for some important notes on\n creating *hashable* objects which support custom comparison\n operations and are usable as dictionary keys.\n\n There are no swapped-argument versions of these methods (to be used\n when the left argument does not support the operation but the right\n argument does); rather, ``__lt__()`` and ``__gt__()`` are each\n other\'s reflection, ``__le__()`` and ``__ge__()`` are each other\'s\n reflection, and ``__eq__()`` and ``__ne__()`` are their own\n reflection.\n\n Arguments to rich comparison methods are never coerced.\n\n To automatically generate ordering operations from a single root\n operation, see ``functools.total_ordering()``.\n\nobject.__hash__(self)\n\n Called by built-in function ``hash()`` and for operations on\n members of hashed collections including ``set``, ``frozenset``, and\n ``dict``. ``__hash__()`` should return an integer. The only\n required property is that objects which compare equal have the same\n hash value; it is advised to somehow mix together (e.g. using\n exclusive or) the hash values for the components of the object that\n also play a part in comparison of objects.\n\n If a class does not define an ``__eq__()`` method it should not\n define a ``__hash__()`` operation either; if it defines\n ``__eq__()`` but not ``__hash__()``, its instances will not be\n usable as items in hashable collections. If a class defines\n mutable objects and implements an ``__eq__()`` method, it should\n not implement ``__hash__()``, since the implementation of hashable\n collections requires that a key\'s hash value is immutable (if the\n object\'s hash value changes, it will be in the wrong hash bucket).\n\n User-defined classes have ``__eq__()`` and ``__hash__()`` methods\n by default; with them, all objects compare unequal (except with\n themselves) and ``x.__hash__()`` returns ``id(x)``.\n\n Classes which inherit a ``__hash__()`` method from a parent class\n but change the meaning of ``__eq__()`` such that the hash value\n returned is no longer appropriate (e.g. by switching to a value-\n based concept of equality instead of the default identity based\n equality) can explicitly flag themselves as being unhashable by\n setting ``__hash__ = None`` in the class definition. Doing so means\n that not only will instances of the class raise an appropriate\n ``TypeError`` when a program attempts to retrieve their hash value,\n but they will also be correctly identified as unhashable when\n checking ``isinstance(obj, collections.Hashable)`` (unlike classes\n which define their own ``__hash__()`` to explicitly raise\n ``TypeError``).\n\n If a class that overrides ``__eq__()`` needs to retain the\n implementation of ``__hash__()`` from a parent class, the\n interpreter must be told this explicitly by setting ``__hash__ =\n .__hash__``. Otherwise the inheritance of\n ``__hash__()`` will be blocked, just as if ``__hash__`` had been\n explicitly set to ``None``.\n\nobject.__bool__(self)\n\n Called to implement truth value testing and the built-in operation\n ``bool()``; should return ``False`` or ``True``. When this method\n is not defined, ``__len__()`` is called, if it is defined, and the\n object is considered true if its result is nonzero. If a class\n defines neither ``__len__()`` nor ``__bool__()``, all its instances\n are considered true.\n\n\nCustomizing attribute access\n============================\n\nThe following methods can be defined to customize the meaning of\nattribute access (use of, assignment to, or deletion of ``x.name``)\nfor class instances.\n\nobject.__getattr__(self, name)\n\n Called when an attribute lookup has not found the attribute in the\n usual places (i.e. it is not an instance attribute nor is it found\n in the class tree for ``self``). ``name`` is the attribute name.\n This method should return the (computed) attribute value or raise\n an ``AttributeError`` exception.\n\n Note that if the attribute is found through the normal mechanism,\n ``__getattr__()`` is not called. (This is an intentional asymmetry\n between ``__getattr__()`` and ``__setattr__()``.) This is done both\n for efficiency reasons and because otherwise ``__getattr__()``\n would have no way to access other attributes of the instance. Note\n that at least for instance variables, you can fake total control by\n not inserting any values in the instance attribute dictionary (but\n instead inserting them in another object). See the\n ``__getattribute__()`` method below for a way to actually get total\n control over attribute access.\n\nobject.__getattribute__(self, name)\n\n Called unconditionally to implement attribute accesses for\n instances of the class. If the class also defines\n ``__getattr__()``, the latter will not be called unless\n ``__getattribute__()`` either calls it explicitly or raises an\n ``AttributeError``. This method should return the (computed)\n attribute value or raise an ``AttributeError`` exception. In order\n to avoid infinite recursion in this method, its implementation\n should always call the base class method with the same name to\n access any attributes it needs, for example,\n ``object.__getattribute__(self, name)``.\n\n Note: This method may still be bypassed when looking up special methods\n as the result of implicit invocation via language syntax or\n built-in functions. See *Special method lookup*.\n\nobject.__setattr__(self, name, value)\n\n Called when an attribute assignment is attempted. This is called\n instead of the normal mechanism (i.e. store the value in the\n instance dictionary). *name* is the attribute name, *value* is the\n value to be assigned to it.\n\n If ``__setattr__()`` wants to assign to an instance attribute, it\n should call the base class method with the same name, for example,\n ``object.__setattr__(self, name, value)``.\n\nobject.__delattr__(self, name)\n\n Like ``__setattr__()`` but for attribute deletion instead of\n assignment. This should only be implemented if ``del obj.name`` is\n meaningful for the object.\n\nobject.__dir__(self)\n\n Called when ``dir()`` is called on the object. A list must be\n returned.\n\n\nImplementing Descriptors\n------------------------\n\nThe following methods only apply when an instance of the class\ncontaining the method (a so-called *descriptor* class) appears in the\nclass dictionary of another class, known as the *owner* class. In the\nexamples below, "the attribute" refers to the attribute whose name is\nthe key of the property in the owner class\' ``__dict__``.\n\nobject.__get__(self, instance, owner)\n\n Called to get the attribute of the owner class (class attribute\n access) or of an instance of that class (instance attribute\n access). *owner* is always the owner class, while *instance* is the\n instance that the attribute was accessed through, or ``None`` when\n the attribute is accessed through the *owner*. This method should\n return the (computed) attribute value or raise an\n ``AttributeError`` exception.\n\nobject.__set__(self, instance, value)\n\n Called to set the attribute on an instance *instance* of the owner\n class to a new value, *value*.\n\nobject.__delete__(self, instance)\n\n Called to delete the attribute on an instance *instance* of the\n owner class.\n\n\nInvoking Descriptors\n--------------------\n\nIn general, a descriptor is an object attribute with "binding\nbehavior", one whose attribute access has been overridden by methods\nin the descriptor protocol: ``__get__()``, ``__set__()``, and\n``__delete__()``. If any of those methods are defined for an object,\nit is said to be a descriptor.\n\nThe default behavior for attribute access is to get, set, or delete\nthe attribute from an object\'s dictionary. For instance, ``a.x`` has a\nlookup chain starting with ``a.__dict__[\'x\']``, then\n``type(a).__dict__[\'x\']``, and continuing through the base classes of\n``type(a)`` excluding metaclasses.\n\nHowever, if the looked-up value is an object defining one of the\ndescriptor methods, then Python may override the default behavior and\ninvoke the descriptor method instead. Where this occurs in the\nprecedence chain depends on which descriptor methods were defined and\nhow they were called.\n\nThe starting point for descriptor invocation is a binding, ``a.x``.\nHow the arguments are assembled depends on ``a``:\n\nDirect Call\n The simplest and least common call is when user code directly\n invokes a descriptor method: ``x.__get__(a)``.\n\nInstance Binding\n If binding to an object instance, ``a.x`` is transformed into the\n call: ``type(a).__dict__[\'x\'].__get__(a, type(a))``.\n\nClass Binding\n If binding to a class, ``A.x`` is transformed into the call:\n ``A.__dict__[\'x\'].__get__(None, A)``.\n\nSuper Binding\n If ``a`` is an instance of ``super``, then the binding ``super(B,\n obj).m()`` searches ``obj.__class__.__mro__`` for the base class\n ``A`` immediately preceding ``B`` and then invokes the descriptor\n with the call: ``A.__dict__[\'m\'].__get__(obj, A)``.\n\nFor instance bindings, the precedence of descriptor invocation depends\non the which descriptor methods are defined. A descriptor can define\nany combination of ``__get__()``, ``__set__()`` and ``__delete__()``.\nIf it does not define ``__get__()``, then accessing the attribute will\nreturn the descriptor object itself unless there is a value in the\nobject\'s instance dictionary. If the descriptor defines ``__set__()``\nand/or ``__delete__()``, it is a data descriptor; if it defines\nneither, it is a non-data descriptor. Normally, data descriptors\ndefine both ``__get__()`` and ``__set__()``, while non-data\ndescriptors have just the ``__get__()`` method. Data descriptors with\n``__set__()`` and ``__get__()`` defined always override a redefinition\nin an instance dictionary. In contrast, non-data descriptors can be\noverridden by instances.\n\nPython methods (including ``staticmethod()`` and ``classmethod()``)\nare implemented as non-data descriptors. Accordingly, instances can\nredefine and override methods. This allows individual instances to\nacquire behaviors that differ from other instances of the same class.\n\nThe ``property()`` function is implemented as a data descriptor.\nAccordingly, instances cannot override the behavior of a property.\n\n\n__slots__\n---------\n\nBy default, instances of classes have a dictionary for attribute\nstorage. This wastes space for objects having very few instance\nvariables. The space consumption can become acute when creating large\nnumbers of instances.\n\nThe default can be overridden by defining *__slots__* in a class\ndefinition. The *__slots__* declaration takes a sequence of instance\nvariables and reserves just enough space in each instance to hold a\nvalue for each variable. Space is saved because *__dict__* is not\ncreated for each instance.\n\nobject.__slots__\n\n This class variable can be assigned a string, iterable, or sequence\n of strings with variable names used by instances. If defined in a\n class, *__slots__* reserves space for the declared variables and\n prevents the automatic creation of *__dict__* and *__weakref__* for\n each instance.\n\n\nNotes on using *__slots__*\n~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n* When inheriting from a class without *__slots__*, the *__dict__*\n attribute of that class will always be accessible, so a *__slots__*\n definition in the subclass is meaningless.\n\n* Without a *__dict__* variable, instances cannot be assigned new\n variables not listed in the *__slots__* definition. Attempts to\n assign to an unlisted variable name raises ``AttributeError``. If\n dynamic assignment of new variables is desired, then add\n ``\'__dict__\'`` to the sequence of strings in the *__slots__*\n declaration.\n\n* Without a *__weakref__* variable for each instance, classes defining\n *__slots__* do not support weak references to its instances. If weak\n reference support is needed, then add ``\'__weakref__\'`` to the\n sequence of strings in the *__slots__* declaration.\n\n* *__slots__* are implemented at the class level by creating\n descriptors (*Implementing Descriptors*) for each variable name. As\n a result, class attributes cannot be used to set default values for\n instance variables defined by *__slots__*; otherwise, the class\n attribute would overwrite the descriptor assignment.\n\n* The action of a *__slots__* declaration is limited to the class\n where it is defined. As a result, subclasses will have a *__dict__*\n unless they also define *__slots__* (which must only contain names\n of any *additional* slots).\n\n* If a class defines a slot also defined in a base class, the instance\n variable defined by the base class slot is inaccessible (except by\n retrieving its descriptor directly from the base class). This\n renders the meaning of the program undefined. In the future, a\n check may be added to prevent this.\n\n* Nonempty *__slots__* does not work for classes derived from\n "variable-length" built-in types such as ``int``, ``str`` and\n ``tuple``.\n\n* Any non-string iterable may be assigned to *__slots__*. Mappings may\n also be used; however, in the future, special meaning may be\n assigned to the values corresponding to each key.\n\n* *__class__* assignment works only if both classes have the same\n *__slots__*.\n\n\nCustomizing class creation\n==========================\n\nBy default, classes are constructed using ``type()``. A class\ndefinition is read into a separate namespace and the value of class\nname is bound to the result of ``type(name, bases, dict)``.\n\nWhen the class definition is read, if a callable ``metaclass`` keyword\nargument is passed after the bases in the class definition, the\ncallable given will be called instead of ``type()``. If other keyword\narguments are passed, they will also be passed to the metaclass. This\nallows classes or functions to be written which monitor or alter the\nclass creation process:\n\n* Modifying the class dictionary prior to the class being created.\n\n* Returning an instance of another class -- essentially performing the\n role of a factory function.\n\nThese steps will have to be performed in the metaclass\'s ``__new__()``\nmethod -- ``type.__new__()`` can then be called from this method to\ncreate a class with different properties. This example adds a new\nelement to the class dictionary before creating the class:\n\n class metacls(type):\n def __new__(mcs, name, bases, dict):\n dict[\'foo\'] = \'metacls was here\'\n return type.__new__(mcs, name, bases, dict)\n\nYou can of course also override other class methods (or add new\nmethods); for example defining a custom ``__call__()`` method in the\nmetaclass allows custom behavior when the class is called, e.g. not\nalways creating a new instance.\n\nIf the metaclass has a ``__prepare__()`` attribute (usually\nimplemented as a class or static method), it is called before the\nclass body is evaluated with the name of the class and a tuple of its\nbases for arguments. It should return an object that supports the\nmapping interface that will be used to store the namespace of the\nclass. The default is a plain dictionary. This could be used, for\nexample, to keep track of the order that class attributes are declared\nin by returning an ordered dictionary.\n\nThe appropriate metaclass is determined by the following precedence\nrules:\n\n* If the ``metaclass`` keyword argument is passed with the bases, it\n is used.\n\n* Otherwise, if there is at least one base class, its metaclass is\n used.\n\n* Otherwise, the default metaclass (``type``) is used.\n\nThe potential uses for metaclasses are boundless. Some ideas that have\nbeen explored including logging, interface checking, automatic\ndelegation, automatic property creation, proxies, frameworks, and\nautomatic resource locking/synchronization.\n\nHere is an example of a metaclass that uses an\n``collections.OrderedDict`` to remember the order that class members\nwere defined:\n\n class OrderedClass(type):\n\n @classmethod\n def __prepare__(metacls, name, bases, **kwds):\n return collections.OrderedDict()\n\n def __new__(cls, name, bases, classdict):\n result = type.__new__(cls, name, bases, dict(classdict))\n result.members = tuple(classdict)\n return result\n\n class A(metaclass=OrderedClass):\n def one(self): pass\n def two(self): pass\n def three(self): pass\n def four(self): pass\n\n >>> A.members\n (\'__module__\', \'one\', \'two\', \'three\', \'four\')\n\nWhen the class definition for *A* gets executed, the process begins\nwith calling the metaclass\'s ``__prepare__()`` method which returns an\nempty ``collections.OrderedDict``. That mapping records the methods\nand attributes of *A* as they are defined within the body of the class\nstatement. Once those definitions are executed, the ordered dictionary\nis fully populated and the metaclass\'s ``__new__()`` method gets\ninvoked. That method builds the new type and it saves the ordered\ndictionary keys in an attribute called ``members``.\n\n\nCustomizing instance and subclass checks\n========================================\n\nThe following methods are used to override the default behavior of the\n``isinstance()`` and ``issubclass()`` built-in functions.\n\nIn particular, the metaclass ``abc.ABCMeta`` implements these methods\nin order to allow the addition of Abstract Base Classes (ABCs) as\n"virtual base classes" to any class or type (including built-in\ntypes), including other ABCs.\n\nclass.__instancecheck__(self, instance)\n\n Return true if *instance* should be considered a (direct or\n indirect) instance of *class*. If defined, called to implement\n ``isinstance(instance, class)``.\n\nclass.__subclasscheck__(self, subclass)\n\n Return true if *subclass* should be considered a (direct or\n indirect) subclass of *class*. If defined, called to implement\n ``issubclass(subclass, class)``.\n\nNote that these methods are looked up on the type (metaclass) of a\nclass. They cannot be defined as class methods in the actual class.\nThis is consistent with the lookup of special methods that are called\non instances, only in this case the instance is itself a class.\n\nSee also:\n\n **PEP 3119** - Introducing Abstract Base Classes\n Includes the specification for customizing ``isinstance()`` and\n ``issubclass()`` behavior through ``__instancecheck__()`` and\n ``__subclasscheck__()``, with motivation for this functionality\n in the context of adding Abstract Base Classes (see the ``abc``\n module) to the language.\n\n\nEmulating callable objects\n==========================\n\nobject.__call__(self[, args...])\n\n Called when the instance is "called" as a function; if this method\n is defined, ``x(arg1, arg2, ...)`` is a shorthand for\n ``x.__call__(arg1, arg2, ...)``.\n\n\nEmulating container types\n=========================\n\nThe following methods can be defined to implement container objects.\nContainers usually are sequences (such as lists or tuples) or mappings\n(like dictionaries), but can represent other containers as well. The\nfirst set of methods is used either to emulate a sequence or to\nemulate a mapping; the difference is that for a sequence, the\nallowable keys should be the integers *k* for which ``0 <= k < N``\nwhere *N* is the length of the sequence, or slice objects, which\ndefine a range of items. It is also recommended that mappings provide\nthe methods ``keys()``, ``values()``, ``items()``, ``get()``,\n``clear()``, ``setdefault()``, ``pop()``, ``popitem()``, ``copy()``,\nand ``update()`` behaving similar to those for Python\'s standard\ndictionary objects. The ``collections`` module provides a\n``MutableMapping`` abstract base class to help create those methods\nfrom a base set of ``__getitem__()``, ``__setitem__()``,\n``__delitem__()``, and ``keys()``. Mutable sequences should provide\nmethods ``append()``, ``count()``, ``index()``, ``extend()``,\n``insert()``, ``pop()``, ``remove()``, ``reverse()`` and ``sort()``,\nlike Python standard list objects. Finally, sequence types should\nimplement addition (meaning concatenation) and multiplication (meaning\nrepetition) by defining the methods ``__add__()``, ``__radd__()``,\n``__iadd__()``, ``__mul__()``, ``__rmul__()`` and ``__imul__()``\ndescribed below; they should not define other numerical operators. It\nis recommended that both mappings and sequences implement the\n``__contains__()`` method to allow efficient use of the ``in``\noperator; for mappings, ``in`` should search the mapping\'s keys; for\nsequences, it should search through the values. It is further\nrecommended that both mappings and sequences implement the\n``__iter__()`` method to allow efficient iteration through the\ncontainer; for mappings, ``__iter__()`` should be the same as\n``keys()``; for sequences, it should iterate through the values.\n\nobject.__len__(self)\n\n Called to implement the built-in function ``len()``. Should return\n the length of the object, an integer ``>=`` 0. Also, an object\n that doesn\'t define a ``__bool__()`` method and whose ``__len__()``\n method returns zero is considered to be false in a Boolean context.\n\nNote: Slicing is done exclusively with the following three methods. A\n call like\n\n a[1:2] = b\n\n is translated to\n\n a[slice(1, 2, None)] = b\n\n and so forth. Missing slice items are always filled in with\n ``None``.\n\nobject.__getitem__(self, key)\n\n Called to implement evaluation of ``self[key]``. For sequence\n types, the accepted keys should be integers and slice objects.\n Note that the special interpretation of negative indexes (if the\n class wishes to emulate a sequence type) is up to the\n ``__getitem__()`` method. If *key* is of an inappropriate type,\n ``TypeError`` may be raised; if of a value outside the set of\n indexes for the sequence (after any special interpretation of\n negative values), ``IndexError`` should be raised. For mapping\n types, if *key* is missing (not in the container), ``KeyError``\n should be raised.\n\n Note: ``for`` loops expect that an ``IndexError`` will be raised for\n illegal indexes to allow proper detection of the end of the\n sequence.\n\nobject.__setitem__(self, key, value)\n\n Called to implement assignment to ``self[key]``. Same note as for\n ``__getitem__()``. This should only be implemented for mappings if\n the objects support changes to the values for keys, or if new keys\n can be added, or for sequences if elements can be replaced. The\n same exceptions should be raised for improper *key* values as for\n the ``__getitem__()`` method.\n\nobject.__delitem__(self, key)\n\n Called to implement deletion of ``self[key]``. Same note as for\n ``__getitem__()``. This should only be implemented for mappings if\n the objects support removal of keys, or for sequences if elements\n can be removed from the sequence. The same exceptions should be\n raised for improper *key* values as for the ``__getitem__()``\n method.\n\nobject.__iter__(self)\n\n This method is called when an iterator is required for a container.\n This method should return a new iterator object that can iterate\n over all the objects in the container. For mappings, it should\n iterate over the keys of the container, and should also be made\n available as the method ``keys()``.\n\n Iterator objects also need to implement this method; they are\n required to return themselves. For more information on iterator\n objects, see *Iterator Types*.\n\nobject.__reversed__(self)\n\n Called (if present) by the ``reversed()`` built-in to implement\n reverse iteration. It should return a new iterator object that\n iterates over all the objects in the container in reverse order.\n\n If the ``__reversed__()`` method is not provided, the\n ``reversed()`` built-in will fall back to using the sequence\n protocol (``__len__()`` and ``__getitem__()``). Objects that\n support the sequence protocol should only provide\n ``__reversed__()`` if they can provide an implementation that is\n more efficient than the one provided by ``reversed()``.\n\nThe membership test operators (``in`` and ``not in``) are normally\nimplemented as an iteration through a sequence. However, container\nobjects can supply the following special method with a more efficient\nimplementation, which also does not require the object be a sequence.\n\nobject.__contains__(self, item)\n\n Called to implement membership test operators. Should return true\n if *item* is in *self*, false otherwise. For mapping objects, this\n should consider the keys of the mapping rather than the values or\n the key-item pairs.\n\n For objects that don\'t define ``__contains__()``, the membership\n test first tries iteration via ``__iter__()``, then the old\n sequence iteration protocol via ``__getitem__()``, see *this\n section in the language reference*.\n\n\nEmulating numeric types\n=======================\n\nThe following methods can be defined to emulate numeric objects.\nMethods corresponding to operations that are not supported by the\nparticular kind of number implemented (e.g., bitwise operations for\nnon-integral numbers) should be left undefined.\n\nobject.__add__(self, other)\nobject.__sub__(self, other)\nobject.__mul__(self, other)\nobject.__truediv__(self, other)\nobject.__floordiv__(self, other)\nobject.__mod__(self, other)\nobject.__divmod__(self, other)\nobject.__pow__(self, other[, modulo])\nobject.__lshift__(self, other)\nobject.__rshift__(self, other)\nobject.__and__(self, other)\nobject.__xor__(self, other)\nobject.__or__(self, other)\n\n These methods are called to implement the binary arithmetic\n operations (``+``, ``-``, ``*``, ``/``, ``//``, ``%``,\n ``divmod()``, ``pow()``, ``**``, ``<<``, ``>>``, ``&``, ``^``,\n ``|``). For instance, to evaluate the expression ``x + y``, where\n *x* is an instance of a class that has an ``__add__()`` method,\n ``x.__add__(y)`` is called. The ``__divmod__()`` method should be\n the equivalent to using ``__floordiv__()`` and ``__mod__()``; it\n should not be related to ``__truediv__()``. Note that\n ``__pow__()`` should be defined to accept an optional third\n argument if the ternary version of the built-in ``pow()`` function\n is to be supported.\n\n If one of those methods does not support the operation with the\n supplied arguments, it should return ``NotImplemented``.\n\nobject.__radd__(self, other)\nobject.__rsub__(self, other)\nobject.__rmul__(self, other)\nobject.__rtruediv__(self, other)\nobject.__rfloordiv__(self, other)\nobject.__rmod__(self, other)\nobject.__rdivmod__(self, other)\nobject.__rpow__(self, other)\nobject.__rlshift__(self, other)\nobject.__rrshift__(self, other)\nobject.__rand__(self, other)\nobject.__rxor__(self, other)\nobject.__ror__(self, other)\n\n These methods are called to implement the binary arithmetic\n operations (``+``, ``-``, ``*``, ``/``, ``//``, ``%``,\n ``divmod()``, ``pow()``, ``**``, ``<<``, ``>>``, ``&``, ``^``,\n ``|``) with reflected (swapped) operands. These functions are only\n called if the left operand does not support the corresponding\n operation and the operands are of different types. [2] For\n instance, to evaluate the expression ``x - y``, where *y* is an\n instance of a class that has an ``__rsub__()`` method,\n ``y.__rsub__(x)`` is called if ``x.__sub__(y)`` returns\n *NotImplemented*.\n\n Note that ternary ``pow()`` will not try calling ``__rpow__()``\n (the coercion rules would become too complicated).\n\n Note: If the right operand\'s type is a subclass of the left operand\'s\n type and that subclass provides the reflected method for the\n operation, this method will be called before the left operand\'s\n non-reflected method. This behavior allows subclasses to\n override their ancestors\' operations.\n\nobject.__iadd__(self, other)\nobject.__isub__(self, other)\nobject.__imul__(self, other)\nobject.__itruediv__(self, other)\nobject.__ifloordiv__(self, other)\nobject.__imod__(self, other)\nobject.__ipow__(self, other[, modulo])\nobject.__ilshift__(self, other)\nobject.__irshift__(self, other)\nobject.__iand__(self, other)\nobject.__ixor__(self, other)\nobject.__ior__(self, other)\n\n These methods are called to implement the augmented arithmetic\n assignments (``+=``, ``-=``, ``*=``, ``/=``, ``//=``, ``%=``,\n ``**=``, ``<<=``, ``>>=``, ``&=``, ``^=``, ``|=``). These methods\n should attempt to do the operation in-place (modifying *self*) and\n return the result (which could be, but does not have to be,\n *self*). If a specific method is not defined, the augmented\n assignment falls back to the normal methods. For instance, to\n execute the statement ``x += y``, where *x* is an instance of a\n class that has an ``__iadd__()`` method, ``x.__iadd__(y)`` is\n called. If *x* is an instance of a class that does not define a\n ``__iadd__()`` method, ``x.__add__(y)`` and ``y.__radd__(x)`` are\n considered, as with the evaluation of ``x + y``.\n\nobject.__neg__(self)\nobject.__pos__(self)\nobject.__abs__(self)\nobject.__invert__(self)\n\n Called to implement the unary arithmetic operations (``-``, ``+``,\n ``abs()`` and ``~``).\n\nobject.__complex__(self)\nobject.__int__(self)\nobject.__float__(self)\nobject.__round__(self[, n])\n\n Called to implement the built-in functions ``complex()``,\n ``int()``, ``float()`` and ``round()``. Should return a value of\n the appropriate type.\n\nobject.__index__(self)\n\n Called to implement ``operator.index()``. Also called whenever\n Python needs an integer object (such as in slicing, or in the\n built-in ``bin()``, ``hex()`` and ``oct()`` functions). Must return\n an integer.\n\n\nWith Statement Context Managers\n===============================\n\nA *context manager* is an object that defines the runtime context to\nbe established when executing a ``with`` statement. The context\nmanager handles the entry into, and the exit from, the desired runtime\ncontext for the execution of the block of code. Context managers are\nnormally invoked using the ``with`` statement (described in section\n*The with statement*), but can also be used by directly invoking their\nmethods.\n\nTypical uses of context managers include saving and restoring various\nkinds of global state, locking and unlocking resources, closing opened\nfiles, etc.\n\nFor more information on context managers, see *Context Manager Types*.\n\nobject.__enter__(self)\n\n Enter the runtime context related to this object. The ``with``\n statement will bind this method\'s return value to the target(s)\n specified in the ``as`` clause of the statement, if any.\n\nobject.__exit__(self, exc_type, exc_value, traceback)\n\n Exit the runtime context related to this object. The parameters\n describe the exception that caused the context to be exited. If the\n context was exited without an exception, all three arguments will\n be ``None``.\n\n If an exception is supplied, and the method wishes to suppress the\n exception (i.e., prevent it from being propagated), it should\n return a true value. Otherwise, the exception will be processed\n normally upon exit from this method.\n\n Note that ``__exit__()`` methods should not reraise the passed-in\n exception; this is the caller\'s responsibility.\n\nSee also:\n\n **PEP 0343** - The "with" statement\n The specification, background, and examples for the Python\n ``with`` statement.\n\n\nSpecial method lookup\n=====================\n\nFor custom classes, implicit invocations of special methods are only\nguaranteed to work correctly if defined on an object\'s type, not in\nthe object\'s instance dictionary. That behaviour is the reason why\nthe following code raises an exception:\n\n >>> class C:\n ... pass\n ...\n >>> c = C()\n >>> c.__len__ = lambda: 5\n >>> len(c)\n Traceback (most recent call last):\n File "", line 1, in \n TypeError: object of type \'C\' has no len()\n\nThe rationale behind this behaviour lies with a number of special\nmethods such as ``__hash__()`` and ``__repr__()`` that are implemented\nby all objects, including type objects. If the implicit lookup of\nthese methods used the conventional lookup process, they would fail\nwhen invoked on the type object itself:\n\n >>> 1 .__hash__() == hash(1)\n True\n >>> int.__hash__() == hash(int)\n Traceback (most recent call last):\n File "", line 1, in \n TypeError: descriptor \'__hash__\' of \'int\' object needs an argument\n\nIncorrectly attempting to invoke an unbound method of a class in this\nway is sometimes referred to as \'metaclass confusion\', and is avoided\nby bypassing the instance when looking up special methods:\n\n >>> type(1).__hash__(1) == hash(1)\n True\n >>> type(int).__hash__(int) == hash(int)\n True\n\nIn addition to bypassing any instance attributes in the interest of\ncorrectness, implicit special method lookup generally also bypasses\nthe ``__getattribute__()`` method even of the object\'s metaclass:\n\n >>> class Meta(type):\n ... def __getattribute__(*args):\n ... print("Metaclass getattribute invoked")\n ... return type.__getattribute__(*args)\n ...\n >>> class C(object, metaclass=Meta):\n ... def __len__(self):\n ... return 10\n ... def __getattribute__(*args):\n ... print("Class getattribute invoked")\n ... return object.__getattribute__(*args)\n ...\n >>> c = C()\n >>> c.__len__() # Explicit lookup via instance\n Class getattribute invoked\n 10\n >>> type(c).__len__(c) # Explicit lookup via type\n Metaclass getattribute invoked\n 10\n >>> len(c) # Implicit lookup\n 10\n\nBypassing the ``__getattribute__()`` machinery in this fashion\nprovides significant scope for speed optimisations within the\ninterpreter, at the cost of some flexibility in the handling of\nspecial methods (the special method *must* be set on the class object\nitself in order to be consistently invoked by the interpreter).\n\n-[ Footnotes ]-\n\n[1] It *is* possible in some cases to change an object\'s type, under\n certain controlled conditions. It generally isn\'t a good idea\n though, since it can lead to some very strange behaviour if it is\n handled incorrectly.\n\n[2] For operands of the same type, it is assumed that if the non-\n reflected method (such as ``__add__()``) fails the operation is\n not supported, which is why the reflected method is not called.\n', + 'specialnames': '\nSpecial method names\n********************\n\nA class can implement certain operations that are invoked by special\nsyntax (such as arithmetic operations or subscripting and slicing) by\ndefining methods with special names. This is Python\'s approach to\n*operator overloading*, allowing classes to define their own behavior\nwith respect to language operators. For instance, if a class defines\na method named ``__getitem__()``, and ``x`` is an instance of this\nclass, then ``x[i]`` is roughly equivalent to ``type(x).__getitem__(x,\ni)``. Except where mentioned, attempts to execute an operation raise\nan exception when no appropriate method is defined (typically\n``AttributeError`` or ``TypeError``).\n\nWhen implementing a class that emulates any built-in type, it is\nimportant that the emulation only be implemented to the degree that it\nmakes sense for the object being modelled. For example, some\nsequences may work well with retrieval of individual elements, but\nextracting a slice may not make sense. (One example of this is the\n``NodeList`` interface in the W3C\'s Document Object Model.)\n\n\nBasic customization\n===================\n\nobject.__new__(cls[, ...])\n\n Called to create a new instance of class *cls*. ``__new__()`` is a\n static method (special-cased so you need not declare it as such)\n that takes the class of which an instance was requested as its\n first argument. The remaining arguments are those passed to the\n object constructor expression (the call to the class). The return\n value of ``__new__()`` should be the new object instance (usually\n an instance of *cls*).\n\n Typical implementations create a new instance of the class by\n invoking the superclass\'s ``__new__()`` method using\n ``super(currentclass, cls).__new__(cls[, ...])`` with appropriate\n arguments and then modifying the newly-created instance as\n necessary before returning it.\n\n If ``__new__()`` returns an instance of *cls*, then the new\n instance\'s ``__init__()`` method will be invoked like\n ``__init__(self[, ...])``, where *self* is the new instance and the\n remaining arguments are the same as were passed to ``__new__()``.\n\n If ``__new__()`` does not return an instance of *cls*, then the new\n instance\'s ``__init__()`` method will not be invoked.\n\n ``__new__()`` is intended mainly to allow subclasses of immutable\n types (like int, str, or tuple) to customize instance creation. It\n is also commonly overridden in custom metaclasses in order to\n customize class creation.\n\nobject.__init__(self[, ...])\n\n Called when the instance is created. The arguments are those\n passed to the class constructor expression. If a base class has an\n ``__init__()`` method, the derived class\'s ``__init__()`` method,\n if any, must explicitly call it to ensure proper initialization of\n the base class part of the instance; for example:\n ``BaseClass.__init__(self, [args...])``. As a special constraint\n on constructors, no value may be returned; doing so will cause a\n ``TypeError`` to be raised at runtime.\n\nobject.__del__(self)\n\n Called when the instance is about to be destroyed. This is also\n called a destructor. If a base class has a ``__del__()`` method,\n the derived class\'s ``__del__()`` method, if any, must explicitly\n call it to ensure proper deletion of the base class part of the\n instance. Note that it is possible (though not recommended!) for\n the ``__del__()`` method to postpone destruction of the instance by\n creating a new reference to it. It may then be called at a later\n time when this new reference is deleted. It is not guaranteed that\n ``__del__()`` methods are called for objects that still exist when\n the interpreter exits.\n\n Note: ``del x`` doesn\'t directly call ``x.__del__()`` --- the former\n decrements the reference count for ``x`` by one, and the latter\n is only called when ``x``\'s reference count reaches zero. Some\n common situations that may prevent the reference count of an\n object from going to zero include: circular references between\n objects (e.g., a doubly-linked list or a tree data structure with\n parent and child pointers); a reference to the object on the\n stack frame of a function that caught an exception (the traceback\n stored in ``sys.exc_info()[2]`` keeps the stack frame alive); or\n a reference to the object on the stack frame that raised an\n unhandled exception in interactive mode (the traceback stored in\n ``sys.last_traceback`` keeps the stack frame alive). The first\n situation can only be remedied by explicitly breaking the cycles;\n the latter two situations can be resolved by storing ``None`` in\n ``sys.last_traceback``. Circular references which are garbage are\n detected when the option cycle detector is enabled (it\'s on by\n default), but can only be cleaned up if there are no Python-\n level ``__del__()`` methods involved. Refer to the documentation\n for the ``gc`` module for more information about how\n ``__del__()`` methods are handled by the cycle detector,\n particularly the description of the ``garbage`` value.\n\n Warning: Due to the precarious circumstances under which ``__del__()``\n methods are invoked, exceptions that occur during their execution\n are ignored, and a warning is printed to ``sys.stderr`` instead.\n Also, when ``__del__()`` is invoked in response to a module being\n deleted (e.g., when execution of the program is done), other\n globals referenced by the ``__del__()`` method may already have\n been deleted or in the process of being torn down (e.g. the\n import machinery shutting down). For this reason, ``__del__()``\n methods should do the absolute minimum needed to maintain\n external invariants. Starting with version 1.5, Python\n guarantees that globals whose name begins with a single\n underscore are deleted from their module before other globals are\n deleted; if no other references to such globals exist, this may\n help in assuring that imported modules are still available at the\n time when the ``__del__()`` method is called.\n\nobject.__repr__(self)\n\n Called by the ``repr()`` built-in function to compute the\n "official" string representation of an object. If at all possible,\n this should look like a valid Python expression that could be used\n to recreate an object with the same value (given an appropriate\n environment). If this is not possible, a string of the form\n ``<...some useful description...>`` should be returned. The return\n value must be a string object. If a class defines ``__repr__()``\n but not ``__str__()``, then ``__repr__()`` is also used when an\n "informal" string representation of instances of that class is\n required.\n\n This is typically used for debugging, so it is important that the\n representation is information-rich and unambiguous.\n\nobject.__str__(self)\n\n Called by the ``str()`` built-in function and by the ``print()``\n function to compute the "informal" string representation of an\n object. This differs from ``__repr__()`` in that it does not have\n to be a valid Python expression: a more convenient or concise\n representation may be used instead. The return value must be a\n string object.\n\nobject.__format__(self, format_spec)\n\n Called by the ``format()`` built-in function (and by extension, the\n ``format()`` method of class ``str``) to produce a "formatted"\n string representation of an object. The ``format_spec`` argument is\n a string that contains a description of the formatting options\n desired. The interpretation of the ``format_spec`` argument is up\n to the type implementing ``__format__()``, however most classes\n will either delegate formatting to one of the built-in types, or\n use a similar formatting option syntax.\n\n See *Format Specification Mini-Language* for a description of the\n standard formatting syntax.\n\n The return value must be a string object.\n\nobject.__lt__(self, other)\nobject.__le__(self, other)\nobject.__eq__(self, other)\nobject.__ne__(self, other)\nobject.__gt__(self, other)\nobject.__ge__(self, other)\n\n These are the so-called "rich comparison" methods. The\n correspondence between operator symbols and method names is as\n follows: ``xy`` calls ``x.__gt__(y)``, and ``x>=y`` calls\n ``x.__ge__(y)``.\n\n A rich comparison method may return the singleton\n ``NotImplemented`` if it does not implement the operation for a\n given pair of arguments. By convention, ``False`` and ``True`` are\n returned for a successful comparison. However, these methods can\n return any value, so if the comparison operator is used in a\n Boolean context (e.g., in the condition of an ``if`` statement),\n Python will call ``bool()`` on the value to determine if the result\n is true or false.\n\n There are no implied relationships among the comparison operators.\n The truth of ``x==y`` does not imply that ``x!=y`` is false.\n Accordingly, when defining ``__eq__()``, one should also define\n ``__ne__()`` so that the operators will behave as expected. See\n the paragraph on ``__hash__()`` for some important notes on\n creating *hashable* objects which support custom comparison\n operations and are usable as dictionary keys.\n\n There are no swapped-argument versions of these methods (to be used\n when the left argument does not support the operation but the right\n argument does); rather, ``__lt__()`` and ``__gt__()`` are each\n other\'s reflection, ``__le__()`` and ``__ge__()`` are each other\'s\n reflection, and ``__eq__()`` and ``__ne__()`` are their own\n reflection.\n\n Arguments to rich comparison methods are never coerced.\n\n To automatically generate ordering operations from a single root\n operation, see ``functools.total_ordering()``.\n\nobject.__hash__(self)\n\n Called by built-in function ``hash()`` and for operations on\n members of hashed collections including ``set``, ``frozenset``, and\n ``dict``. ``__hash__()`` should return an integer. The only\n required property is that objects which compare equal have the same\n hash value; it is advised to somehow mix together (e.g. using\n exclusive or) the hash values for the components of the object that\n also play a part in comparison of objects.\n\n If a class does not define an ``__eq__()`` method it should not\n define a ``__hash__()`` operation either; if it defines\n ``__eq__()`` but not ``__hash__()``, its instances will not be\n usable as items in hashable collections. If a class defines\n mutable objects and implements an ``__eq__()`` method, it should\n not implement ``__hash__()``, since the implementation of hashable\n collections requires that a key\'s hash value is immutable (if the\n object\'s hash value changes, it will be in the wrong hash bucket).\n\n User-defined classes have ``__eq__()`` and ``__hash__()`` methods\n by default; with them, all objects compare unequal (except with\n themselves) and ``x.__hash__()`` returns ``id(x)``.\n\n Classes which inherit a ``__hash__()`` method from a parent class\n but change the meaning of ``__eq__()`` such that the hash value\n returned is no longer appropriate (e.g. by switching to a value-\n based concept of equality instead of the default identity based\n equality) can explicitly flag themselves as being unhashable by\n setting ``__hash__ = None`` in the class definition. Doing so means\n that not only will instances of the class raise an appropriate\n ``TypeError`` when a program attempts to retrieve their hash value,\n but they will also be correctly identified as unhashable when\n checking ``isinstance(obj, collections.Hashable)`` (unlike classes\n which define their own ``__hash__()`` to explicitly raise\n ``TypeError``).\n\n If a class that overrides ``__eq__()`` needs to retain the\n implementation of ``__hash__()`` from a parent class, the\n interpreter must be told this explicitly by setting ``__hash__ =\n .__hash__``. Otherwise the inheritance of\n ``__hash__()`` will be blocked, just as if ``__hash__`` had been\n explicitly set to ``None``.\n\nobject.__bool__(self)\n\n Called to implement truth value testing and the built-in operation\n ``bool()``; should return ``False`` or ``True``. When this method\n is not defined, ``__len__()`` is called, if it is defined, and the\n object is considered true if its result is nonzero. If a class\n defines neither ``__len__()`` nor ``__bool__()``, all its instances\n are considered true.\n\n\nCustomizing attribute access\n============================\n\nThe following methods can be defined to customize the meaning of\nattribute access (use of, assignment to, or deletion of ``x.name``)\nfor class instances.\n\nobject.__getattr__(self, name)\n\n Called when an attribute lookup has not found the attribute in the\n usual places (i.e. it is not an instance attribute nor is it found\n in the class tree for ``self``). ``name`` is the attribute name.\n This method should return the (computed) attribute value or raise\n an ``AttributeError`` exception.\n\n Note that if the attribute is found through the normal mechanism,\n ``__getattr__()`` is not called. (This is an intentional asymmetry\n between ``__getattr__()`` and ``__setattr__()``.) This is done both\n for efficiency reasons and because otherwise ``__getattr__()``\n would have no way to access other attributes of the instance. Note\n that at least for instance variables, you can fake total control by\n not inserting any values in the instance attribute dictionary (but\n instead inserting them in another object). See the\n ``__getattribute__()`` method below for a way to actually get total\n control over attribute access.\n\nobject.__getattribute__(self, name)\n\n Called unconditionally to implement attribute accesses for\n instances of the class. If the class also defines\n ``__getattr__()``, the latter will not be called unless\n ``__getattribute__()`` either calls it explicitly or raises an\n ``AttributeError``. This method should return the (computed)\n attribute value or raise an ``AttributeError`` exception. In order\n to avoid infinite recursion in this method, its implementation\n should always call the base class method with the same name to\n access any attributes it needs, for example,\n ``object.__getattribute__(self, name)``.\n\n Note: This method may still be bypassed when looking up special methods\n as the result of implicit invocation via language syntax or\n built-in functions. See *Special method lookup*.\n\nobject.__setattr__(self, name, value)\n\n Called when an attribute assignment is attempted. This is called\n instead of the normal mechanism (i.e. store the value in the\n instance dictionary). *name* is the attribute name, *value* is the\n value to be assigned to it.\n\n If ``__setattr__()`` wants to assign to an instance attribute, it\n should call the base class method with the same name, for example,\n ``object.__setattr__(self, name, value)``.\n\nobject.__delattr__(self, name)\n\n Like ``__setattr__()`` but for attribute deletion instead of\n assignment. This should only be implemented if ``del obj.name`` is\n meaningful for the object.\n\nobject.__dir__(self)\n\n Called when ``dir()`` is called on the object. A list must be\n returned.\n\n\nImplementing Descriptors\n------------------------\n\nThe following methods only apply when an instance of the class\ncontaining the method (a so-called *descriptor* class) appears in an\n*owner* class (the descriptor must be in either the owner\'s class\ndictionary or in the class dictionary for one of its parents). In the\nexamples below, "the attribute" refers to the attribute whose name is\nthe key of the property in the owner class\' ``__dict__``.\n\nobject.__get__(self, instance, owner)\n\n Called to get the attribute of the owner class (class attribute\n access) or of an instance of that class (instance attribute\n access). *owner* is always the owner class, while *instance* is the\n instance that the attribute was accessed through, or ``None`` when\n the attribute is accessed through the *owner*. This method should\n return the (computed) attribute value or raise an\n ``AttributeError`` exception.\n\nobject.__set__(self, instance, value)\n\n Called to set the attribute on an instance *instance* of the owner\n class to a new value, *value*.\n\nobject.__delete__(self, instance)\n\n Called to delete the attribute on an instance *instance* of the\n owner class.\n\n\nInvoking Descriptors\n--------------------\n\nIn general, a descriptor is an object attribute with "binding\nbehavior", one whose attribute access has been overridden by methods\nin the descriptor protocol: ``__get__()``, ``__set__()``, and\n``__delete__()``. If any of those methods are defined for an object,\nit is said to be a descriptor.\n\nThe default behavior for attribute access is to get, set, or delete\nthe attribute from an object\'s dictionary. For instance, ``a.x`` has a\nlookup chain starting with ``a.__dict__[\'x\']``, then\n``type(a).__dict__[\'x\']``, and continuing through the base classes of\n``type(a)`` excluding metaclasses.\n\nHowever, if the looked-up value is an object defining one of the\ndescriptor methods, then Python may override the default behavior and\ninvoke the descriptor method instead. Where this occurs in the\nprecedence chain depends on which descriptor methods were defined and\nhow they were called.\n\nThe starting point for descriptor invocation is a binding, ``a.x``.\nHow the arguments are assembled depends on ``a``:\n\nDirect Call\n The simplest and least common call is when user code directly\n invokes a descriptor method: ``x.__get__(a)``.\n\nInstance Binding\n If binding to an object instance, ``a.x`` is transformed into the\n call: ``type(a).__dict__[\'x\'].__get__(a, type(a))``.\n\nClass Binding\n If binding to a class, ``A.x`` is transformed into the call:\n ``A.__dict__[\'x\'].__get__(None, A)``.\n\nSuper Binding\n If ``a`` is an instance of ``super``, then the binding ``super(B,\n obj).m()`` searches ``obj.__class__.__mro__`` for the base class\n ``A`` immediately preceding ``B`` and then invokes the descriptor\n with the call: ``A.__dict__[\'m\'].__get__(obj, obj.__class__)``.\n\nFor instance bindings, the precedence of descriptor invocation depends\non the which descriptor methods are defined. A descriptor can define\nany combination of ``__get__()``, ``__set__()`` and ``__delete__()``.\nIf it does not define ``__get__()``, then accessing the attribute will\nreturn the descriptor object itself unless there is a value in the\nobject\'s instance dictionary. If the descriptor defines ``__set__()``\nand/or ``__delete__()``, it is a data descriptor; if it defines\nneither, it is a non-data descriptor. Normally, data descriptors\ndefine both ``__get__()`` and ``__set__()``, while non-data\ndescriptors have just the ``__get__()`` method. Data descriptors with\n``__set__()`` and ``__get__()`` defined always override a redefinition\nin an instance dictionary. In contrast, non-data descriptors can be\noverridden by instances.\n\nPython methods (including ``staticmethod()`` and ``classmethod()``)\nare implemented as non-data descriptors. Accordingly, instances can\nredefine and override methods. This allows individual instances to\nacquire behaviors that differ from other instances of the same class.\n\nThe ``property()`` function is implemented as a data descriptor.\nAccordingly, instances cannot override the behavior of a property.\n\n\n__slots__\n---------\n\nBy default, instances of classes have a dictionary for attribute\nstorage. This wastes space for objects having very few instance\nvariables. The space consumption can become acute when creating large\nnumbers of instances.\n\nThe default can be overridden by defining *__slots__* in a class\ndefinition. The *__slots__* declaration takes a sequence of instance\nvariables and reserves just enough space in each instance to hold a\nvalue for each variable. Space is saved because *__dict__* is not\ncreated for each instance.\n\nobject.__slots__\n\n This class variable can be assigned a string, iterable, or sequence\n of strings with variable names used by instances. If defined in a\n class, *__slots__* reserves space for the declared variables and\n prevents the automatic creation of *__dict__* and *__weakref__* for\n each instance.\n\n\nNotes on using *__slots__*\n~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n* When inheriting from a class without *__slots__*, the *__dict__*\n attribute of that class will always be accessible, so a *__slots__*\n definition in the subclass is meaningless.\n\n* Without a *__dict__* variable, instances cannot be assigned new\n variables not listed in the *__slots__* definition. Attempts to\n assign to an unlisted variable name raises ``AttributeError``. If\n dynamic assignment of new variables is desired, then add\n ``\'__dict__\'`` to the sequence of strings in the *__slots__*\n declaration.\n\n* Without a *__weakref__* variable for each instance, classes defining\n *__slots__* do not support weak references to its instances. If weak\n reference support is needed, then add ``\'__weakref__\'`` to the\n sequence of strings in the *__slots__* declaration.\n\n* *__slots__* are implemented at the class level by creating\n descriptors (*Implementing Descriptors*) for each variable name. As\n a result, class attributes cannot be used to set default values for\n instance variables defined by *__slots__*; otherwise, the class\n attribute would overwrite the descriptor assignment.\n\n* The action of a *__slots__* declaration is limited to the class\n where it is defined. As a result, subclasses will have a *__dict__*\n unless they also define *__slots__* (which must only contain names\n of any *additional* slots).\n\n* If a class defines a slot also defined in a base class, the instance\n variable defined by the base class slot is inaccessible (except by\n retrieving its descriptor directly from the base class). This\n renders the meaning of the program undefined. In the future, a\n check may be added to prevent this.\n\n* Nonempty *__slots__* does not work for classes derived from\n "variable-length" built-in types such as ``int``, ``str`` and\n ``tuple``.\n\n* Any non-string iterable may be assigned to *__slots__*. Mappings may\n also be used; however, in the future, special meaning may be\n assigned to the values corresponding to each key.\n\n* *__class__* assignment works only if both classes have the same\n *__slots__*.\n\n\nCustomizing class creation\n==========================\n\nBy default, classes are constructed using ``type()``. A class\ndefinition is read into a separate namespace and the value of class\nname is bound to the result of ``type(name, bases, dict)``.\n\nWhen the class definition is read, if a callable ``metaclass`` keyword\nargument is passed after the bases in the class definition, the\ncallable given will be called instead of ``type()``. If other keyword\narguments are passed, they will also be passed to the metaclass. This\nallows classes or functions to be written which monitor or alter the\nclass creation process:\n\n* Modifying the class dictionary prior to the class being created.\n\n* Returning an instance of another class -- essentially performing the\n role of a factory function.\n\nThese steps will have to be performed in the metaclass\'s ``__new__()``\nmethod -- ``type.__new__()`` can then be called from this method to\ncreate a class with different properties. This example adds a new\nelement to the class dictionary before creating the class:\n\n class metacls(type):\n def __new__(mcs, name, bases, dict):\n dict[\'foo\'] = \'metacls was here\'\n return type.__new__(mcs, name, bases, dict)\n\nYou can of course also override other class methods (or add new\nmethods); for example defining a custom ``__call__()`` method in the\nmetaclass allows custom behavior when the class is called, e.g. not\nalways creating a new instance.\n\nIf the metaclass has a ``__prepare__()`` attribute (usually\nimplemented as a class or static method), it is called before the\nclass body is evaluated with the name of the class and a tuple of its\nbases for arguments. It should return an object that supports the\nmapping interface that will be used to store the namespace of the\nclass. The default is a plain dictionary. This could be used, for\nexample, to keep track of the order that class attributes are declared\nin by returning an ordered dictionary.\n\nThe appropriate metaclass is determined by the following precedence\nrules:\n\n* If the ``metaclass`` keyword argument is passed with the bases, it\n is used.\n\n* Otherwise, if there is at least one base class, its metaclass is\n used.\n\n* Otherwise, the default metaclass (``type``) is used.\n\nThe potential uses for metaclasses are boundless. Some ideas that have\nbeen explored including logging, interface checking, automatic\ndelegation, automatic property creation, proxies, frameworks, and\nautomatic resource locking/synchronization.\n\nHere is an example of a metaclass that uses an\n``collections.OrderedDict`` to remember the order that class members\nwere defined:\n\n class OrderedClass(type):\n\n @classmethod\n def __prepare__(metacls, name, bases, **kwds):\n return collections.OrderedDict()\n\n def __new__(cls, name, bases, classdict):\n result = type.__new__(cls, name, bases, dict(classdict))\n result.members = tuple(classdict)\n return result\n\n class A(metaclass=OrderedClass):\n def one(self): pass\n def two(self): pass\n def three(self): pass\n def four(self): pass\n\n >>> A.members\n (\'__module__\', \'one\', \'two\', \'three\', \'four\')\n\nWhen the class definition for *A* gets executed, the process begins\nwith calling the metaclass\'s ``__prepare__()`` method which returns an\nempty ``collections.OrderedDict``. That mapping records the methods\nand attributes of *A* as they are defined within the body of the class\nstatement. Once those definitions are executed, the ordered dictionary\nis fully populated and the metaclass\'s ``__new__()`` method gets\ninvoked. That method builds the new type and it saves the ordered\ndictionary keys in an attribute called ``members``.\n\n\nCustomizing instance and subclass checks\n========================================\n\nThe following methods are used to override the default behavior of the\n``isinstance()`` and ``issubclass()`` built-in functions.\n\nIn particular, the metaclass ``abc.ABCMeta`` implements these methods\nin order to allow the addition of Abstract Base Classes (ABCs) as\n"virtual base classes" to any class or type (including built-in\ntypes), including other ABCs.\n\nclass.__instancecheck__(self, instance)\n\n Return true if *instance* should be considered a (direct or\n indirect) instance of *class*. If defined, called to implement\n ``isinstance(instance, class)``.\n\nclass.__subclasscheck__(self, subclass)\n\n Return true if *subclass* should be considered a (direct or\n indirect) subclass of *class*. If defined, called to implement\n ``issubclass(subclass, class)``.\n\nNote that these methods are looked up on the type (metaclass) of a\nclass. They cannot be defined as class methods in the actual class.\nThis is consistent with the lookup of special methods that are called\non instances, only in this case the instance is itself a class.\n\nSee also:\n\n **PEP 3119** - Introducing Abstract Base Classes\n Includes the specification for customizing ``isinstance()`` and\n ``issubclass()`` behavior through ``__instancecheck__()`` and\n ``__subclasscheck__()``, with motivation for this functionality\n in the context of adding Abstract Base Classes (see the ``abc``\n module) to the language.\n\n\nEmulating callable objects\n==========================\n\nobject.__call__(self[, args...])\n\n Called when the instance is "called" as a function; if this method\n is defined, ``x(arg1, arg2, ...)`` is a shorthand for\n ``x.__call__(arg1, arg2, ...)``.\n\n\nEmulating container types\n=========================\n\nThe following methods can be defined to implement container objects.\nContainers usually are sequences (such as lists or tuples) or mappings\n(like dictionaries), but can represent other containers as well. The\nfirst set of methods is used either to emulate a sequence or to\nemulate a mapping; the difference is that for a sequence, the\nallowable keys should be the integers *k* for which ``0 <= k < N``\nwhere *N* is the length of the sequence, or slice objects, which\ndefine a range of items. It is also recommended that mappings provide\nthe methods ``keys()``, ``values()``, ``items()``, ``get()``,\n``clear()``, ``setdefault()``, ``pop()``, ``popitem()``, ``copy()``,\nand ``update()`` behaving similar to those for Python\'s standard\ndictionary objects. The ``collections`` module provides a\n``MutableMapping`` abstract base class to help create those methods\nfrom a base set of ``__getitem__()``, ``__setitem__()``,\n``__delitem__()``, and ``keys()``. Mutable sequences should provide\nmethods ``append()``, ``count()``, ``index()``, ``extend()``,\n``insert()``, ``pop()``, ``remove()``, ``reverse()`` and ``sort()``,\nlike Python standard list objects. Finally, sequence types should\nimplement addition (meaning concatenation) and multiplication (meaning\nrepetition) by defining the methods ``__add__()``, ``__radd__()``,\n``__iadd__()``, ``__mul__()``, ``__rmul__()`` and ``__imul__()``\ndescribed below; they should not define other numerical operators. It\nis recommended that both mappings and sequences implement the\n``__contains__()`` method to allow efficient use of the ``in``\noperator; for mappings, ``in`` should search the mapping\'s keys; for\nsequences, it should search through the values. It is further\nrecommended that both mappings and sequences implement the\n``__iter__()`` method to allow efficient iteration through the\ncontainer; for mappings, ``__iter__()`` should be the same as\n``keys()``; for sequences, it should iterate through the values.\n\nobject.__len__(self)\n\n Called to implement the built-in function ``len()``. Should return\n the length of the object, an integer ``>=`` 0. Also, an object\n that doesn\'t define a ``__bool__()`` method and whose ``__len__()``\n method returns zero is considered to be false in a Boolean context.\n\nNote: Slicing is done exclusively with the following three methods. A\n call like\n\n a[1:2] = b\n\n is translated to\n\n a[slice(1, 2, None)] = b\n\n and so forth. Missing slice items are always filled in with\n ``None``.\n\nobject.__getitem__(self, key)\n\n Called to implement evaluation of ``self[key]``. For sequence\n types, the accepted keys should be integers and slice objects.\n Note that the special interpretation of negative indexes (if the\n class wishes to emulate a sequence type) is up to the\n ``__getitem__()`` method. If *key* is of an inappropriate type,\n ``TypeError`` may be raised; if of a value outside the set of\n indexes for the sequence (after any special interpretation of\n negative values), ``IndexError`` should be raised. For mapping\n types, if *key* is missing (not in the container), ``KeyError``\n should be raised.\n\n Note: ``for`` loops expect that an ``IndexError`` will be raised for\n illegal indexes to allow proper detection of the end of the\n sequence.\n\nobject.__setitem__(self, key, value)\n\n Called to implement assignment to ``self[key]``. Same note as for\n ``__getitem__()``. This should only be implemented for mappings if\n the objects support changes to the values for keys, or if new keys\n can be added, or for sequences if elements can be replaced. The\n same exceptions should be raised for improper *key* values as for\n the ``__getitem__()`` method.\n\nobject.__delitem__(self, key)\n\n Called to implement deletion of ``self[key]``. Same note as for\n ``__getitem__()``. This should only be implemented for mappings if\n the objects support removal of keys, or for sequences if elements\n can be removed from the sequence. The same exceptions should be\n raised for improper *key* values as for the ``__getitem__()``\n method.\n\nobject.__iter__(self)\n\n This method is called when an iterator is required for a container.\n This method should return a new iterator object that can iterate\n over all the objects in the container. For mappings, it should\n iterate over the keys of the container, and should also be made\n available as the method ``keys()``.\n\n Iterator objects also need to implement this method; they are\n required to return themselves. For more information on iterator\n objects, see *Iterator Types*.\n\nobject.__reversed__(self)\n\n Called (if present) by the ``reversed()`` built-in to implement\n reverse iteration. It should return a new iterator object that\n iterates over all the objects in the container in reverse order.\n\n If the ``__reversed__()`` method is not provided, the\n ``reversed()`` built-in will fall back to using the sequence\n protocol (``__len__()`` and ``__getitem__()``). Objects that\n support the sequence protocol should only provide\n ``__reversed__()`` if they can provide an implementation that is\n more efficient than the one provided by ``reversed()``.\n\nThe membership test operators (``in`` and ``not in``) are normally\nimplemented as an iteration through a sequence. However, container\nobjects can supply the following special method with a more efficient\nimplementation, which also does not require the object be a sequence.\n\nobject.__contains__(self, item)\n\n Called to implement membership test operators. Should return true\n if *item* is in *self*, false otherwise. For mapping objects, this\n should consider the keys of the mapping rather than the values or\n the key-item pairs.\n\n For objects that don\'t define ``__contains__()``, the membership\n test first tries iteration via ``__iter__()``, then the old\n sequence iteration protocol via ``__getitem__()``, see *this\n section in the language reference*.\n\n\nEmulating numeric types\n=======================\n\nThe following methods can be defined to emulate numeric objects.\nMethods corresponding to operations that are not supported by the\nparticular kind of number implemented (e.g., bitwise operations for\nnon-integral numbers) should be left undefined.\n\nobject.__add__(self, other)\nobject.__sub__(self, other)\nobject.__mul__(self, other)\nobject.__truediv__(self, other)\nobject.__floordiv__(self, other)\nobject.__mod__(self, other)\nobject.__divmod__(self, other)\nobject.__pow__(self, other[, modulo])\nobject.__lshift__(self, other)\nobject.__rshift__(self, other)\nobject.__and__(self, other)\nobject.__xor__(self, other)\nobject.__or__(self, other)\n\n These methods are called to implement the binary arithmetic\n operations (``+``, ``-``, ``*``, ``/``, ``//``, ``%``,\n ``divmod()``, ``pow()``, ``**``, ``<<``, ``>>``, ``&``, ``^``,\n ``|``). For instance, to evaluate the expression ``x + y``, where\n *x* is an instance of a class that has an ``__add__()`` method,\n ``x.__add__(y)`` is called. The ``__divmod__()`` method should be\n the equivalent to using ``__floordiv__()`` and ``__mod__()``; it\n should not be related to ``__truediv__()``. Note that\n ``__pow__()`` should be defined to accept an optional third\n argument if the ternary version of the built-in ``pow()`` function\n is to be supported.\n\n If one of those methods does not support the operation with the\n supplied arguments, it should return ``NotImplemented``.\n\nobject.__radd__(self, other)\nobject.__rsub__(self, other)\nobject.__rmul__(self, other)\nobject.__rtruediv__(self, other)\nobject.__rfloordiv__(self, other)\nobject.__rmod__(self, other)\nobject.__rdivmod__(self, other)\nobject.__rpow__(self, other)\nobject.__rlshift__(self, other)\nobject.__rrshift__(self, other)\nobject.__rand__(self, other)\nobject.__rxor__(self, other)\nobject.__ror__(self, other)\n\n These methods are called to implement the binary arithmetic\n operations (``+``, ``-``, ``*``, ``/``, ``//``, ``%``,\n ``divmod()``, ``pow()``, ``**``, ``<<``, ``>>``, ``&``, ``^``,\n ``|``) with reflected (swapped) operands. These functions are only\n called if the left operand does not support the corresponding\n operation and the operands are of different types. [2] For\n instance, to evaluate the expression ``x - y``, where *y* is an\n instance of a class that has an ``__rsub__()`` method,\n ``y.__rsub__(x)`` is called if ``x.__sub__(y)`` returns\n *NotImplemented*.\n\n Note that ternary ``pow()`` will not try calling ``__rpow__()``\n (the coercion rules would become too complicated).\n\n Note: If the right operand\'s type is a subclass of the left operand\'s\n type and that subclass provides the reflected method for the\n operation, this method will be called before the left operand\'s\n non-reflected method. This behavior allows subclasses to\n override their ancestors\' operations.\n\nobject.__iadd__(self, other)\nobject.__isub__(self, other)\nobject.__imul__(self, other)\nobject.__itruediv__(self, other)\nobject.__ifloordiv__(self, other)\nobject.__imod__(self, other)\nobject.__ipow__(self, other[, modulo])\nobject.__ilshift__(self, other)\nobject.__irshift__(self, other)\nobject.__iand__(self, other)\nobject.__ixor__(self, other)\nobject.__ior__(self, other)\n\n These methods are called to implement the augmented arithmetic\n assignments (``+=``, ``-=``, ``*=``, ``/=``, ``//=``, ``%=``,\n ``**=``, ``<<=``, ``>>=``, ``&=``, ``^=``, ``|=``). These methods\n should attempt to do the operation in-place (modifying *self*) and\n return the result (which could be, but does not have to be,\n *self*). If a specific method is not defined, the augmented\n assignment falls back to the normal methods. For instance, to\n execute the statement ``x += y``, where *x* is an instance of a\n class that has an ``__iadd__()`` method, ``x.__iadd__(y)`` is\n called. If *x* is an instance of a class that does not define a\n ``__iadd__()`` method, ``x.__add__(y)`` and ``y.__radd__(x)`` are\n considered, as with the evaluation of ``x + y``.\n\nobject.__neg__(self)\nobject.__pos__(self)\nobject.__abs__(self)\nobject.__invert__(self)\n\n Called to implement the unary arithmetic operations (``-``, ``+``,\n ``abs()`` and ``~``).\n\nobject.__complex__(self)\nobject.__int__(self)\nobject.__float__(self)\nobject.__round__(self[, n])\n\n Called to implement the built-in functions ``complex()``,\n ``int()``, ``float()`` and ``round()``. Should return a value of\n the appropriate type.\n\nobject.__index__(self)\n\n Called to implement ``operator.index()``. Also called whenever\n Python needs an integer object (such as in slicing, or in the\n built-in ``bin()``, ``hex()`` and ``oct()`` functions). Must return\n an integer.\n\n\nWith Statement Context Managers\n===============================\n\nA *context manager* is an object that defines the runtime context to\nbe established when executing a ``with`` statement. The context\nmanager handles the entry into, and the exit from, the desired runtime\ncontext for the execution of the block of code. Context managers are\nnormally invoked using the ``with`` statement (described in section\n*The with statement*), but can also be used by directly invoking their\nmethods.\n\nTypical uses of context managers include saving and restoring various\nkinds of global state, locking and unlocking resources, closing opened\nfiles, etc.\n\nFor more information on context managers, see *Context Manager Types*.\n\nobject.__enter__(self)\n\n Enter the runtime context related to this object. The ``with``\n statement will bind this method\'s return value to the target(s)\n specified in the ``as`` clause of the statement, if any.\n\nobject.__exit__(self, exc_type, exc_value, traceback)\n\n Exit the runtime context related to this object. The parameters\n describe the exception that caused the context to be exited. If the\n context was exited without an exception, all three arguments will\n be ``None``.\n\n If an exception is supplied, and the method wishes to suppress the\n exception (i.e., prevent it from being propagated), it should\n return a true value. Otherwise, the exception will be processed\n normally upon exit from this method.\n\n Note that ``__exit__()`` methods should not reraise the passed-in\n exception; this is the caller\'s responsibility.\n\nSee also:\n\n **PEP 0343** - The "with" statement\n The specification, background, and examples for the Python\n ``with`` statement.\n\n\nSpecial method lookup\n=====================\n\nFor custom classes, implicit invocations of special methods are only\nguaranteed to work correctly if defined on an object\'s type, not in\nthe object\'s instance dictionary. That behaviour is the reason why\nthe following code raises an exception:\n\n >>> class C:\n ... pass\n ...\n >>> c = C()\n >>> c.__len__ = lambda: 5\n >>> len(c)\n Traceback (most recent call last):\n File "", line 1, in \n TypeError: object of type \'C\' has no len()\n\nThe rationale behind this behaviour lies with a number of special\nmethods such as ``__hash__()`` and ``__repr__()`` that are implemented\nby all objects, including type objects. If the implicit lookup of\nthese methods used the conventional lookup process, they would fail\nwhen invoked on the type object itself:\n\n >>> 1 .__hash__() == hash(1)\n True\n >>> int.__hash__() == hash(int)\n Traceback (most recent call last):\n File "", line 1, in \n TypeError: descriptor \'__hash__\' of \'int\' object needs an argument\n\nIncorrectly attempting to invoke an unbound method of a class in this\nway is sometimes referred to as \'metaclass confusion\', and is avoided\nby bypassing the instance when looking up special methods:\n\n >>> type(1).__hash__(1) == hash(1)\n True\n >>> type(int).__hash__(int) == hash(int)\n True\n\nIn addition to bypassing any instance attributes in the interest of\ncorrectness, implicit special method lookup generally also bypasses\nthe ``__getattribute__()`` method even of the object\'s metaclass:\n\n >>> class Meta(type):\n ... def __getattribute__(*args):\n ... print("Metaclass getattribute invoked")\n ... return type.__getattribute__(*args)\n ...\n >>> class C(object, metaclass=Meta):\n ... def __len__(self):\n ... return 10\n ... def __getattribute__(*args):\n ... print("Class getattribute invoked")\n ... return object.__getattribute__(*args)\n ...\n >>> c = C()\n >>> c.__len__() # Explicit lookup via instance\n Class getattribute invoked\n 10\n >>> type(c).__len__(c) # Explicit lookup via type\n Metaclass getattribute invoked\n 10\n >>> len(c) # Implicit lookup\n 10\n\nBypassing the ``__getattribute__()`` machinery in this fashion\nprovides significant scope for speed optimisations within the\ninterpreter, at the cost of some flexibility in the handling of\nspecial methods (the special method *must* be set on the class object\nitself in order to be consistently invoked by the interpreter).\n\n-[ Footnotes ]-\n\n[1] It *is* possible in some cases to change an object\'s type, under\n certain controlled conditions. It generally isn\'t a good idea\n though, since it can lead to some very strange behaviour if it is\n handled incorrectly.\n\n[2] For operands of the same type, it is assumed that if the non-\n reflected method (such as ``__add__()``) fails the operation is\n not supported, which is why the reflected method is not called.\n', 'string-methods': '\nString Methods\n**************\n\nString objects support the methods listed below.\n\nIn addition, Python\'s strings support the sequence type methods\ndescribed in the *Sequence Types --- str, bytes, bytearray, list,\ntuple, range* section. To output formatted strings, see the *String\nFormatting* section. Also, see the ``re`` module for string functions\nbased on regular expressions.\n\nstr.capitalize()\n\n Return a copy of the string with its first character capitalized\n and the rest lowercased.\n\nstr.center(width[, fillchar])\n\n Return centered in a string of length *width*. Padding is done\n using the specified *fillchar* (default is a space).\n\nstr.count(sub[, start[, end]])\n\n Return the number of non-overlapping occurrences of substring *sub*\n in the range [*start*, *end*]. Optional arguments *start* and\n *end* are interpreted as in slice notation.\n\nstr.encode(encoding="utf-8", errors="strict")\n\n Return an encoded version of the string as a bytes object. Default\n encoding is ``\'utf-8\'``. *errors* may be given to set a different\n error handling scheme. The default for *errors* is ``\'strict\'``,\n meaning that encoding errors raise a ``UnicodeError``. Other\n possible values are ``\'ignore\'``, ``\'replace\'``,\n ``\'xmlcharrefreplace\'``, ``\'backslashreplace\'`` and any other name\n registered via ``codecs.register_error()``, see section *Codec Base\n Classes*. For a list of possible encodings, see section *Standard\n Encodings*.\n\n Changed in version 3.1: Support for keyword arguments added.\n\nstr.endswith(suffix[, start[, end]])\n\n Return ``True`` if the string ends with the specified *suffix*,\n otherwise return ``False``. *suffix* can also be a tuple of\n suffixes to look for. With optional *start*, test beginning at\n that position. With optional *end*, stop comparing at that\n position.\n\nstr.expandtabs([tabsize])\n\n Return a copy of the string where all tab characters are replaced\n by one or more spaces, depending on the current column and the\n given tab size. The column number is reset to zero after each\n newline occurring in the string. If *tabsize* is not given, a tab\n size of ``8`` characters is assumed. This doesn\'t understand other\n non-printing characters or escape sequences.\n\nstr.find(sub[, start[, end]])\n\n Return the lowest index in the string where substring *sub* is\n found, such that *sub* is contained in the slice ``s[start:end]``.\n Optional arguments *start* and *end* are interpreted as in slice\n notation. Return ``-1`` if *sub* is not found.\n\nstr.format(*args, **kwargs)\n\n Perform a string formatting operation. The string on which this\n method is called can contain literal text or replacement fields\n delimited by braces ``{}``. Each replacement field contains either\n the numeric index of a positional argument, or the name of a\n keyword argument. Returns a copy of the string where each\n replacement field is replaced with the string value of the\n corresponding argument.\n\n >>> "The sum of 1 + 2 is {0}".format(1+2)\n \'The sum of 1 + 2 is 3\'\n\n See *Format String Syntax* for a description of the various\n formatting options that can be specified in format strings.\n\nstr.format_map(mapping)\n\n Similar to ``str.format(**mapping)``, except that ``mapping`` is\n used directly and not copied to a ``dict`` . This is useful if for\n example ``mapping`` is a dict subclass:\n\n >>> class Default(dict):\n ... def __missing__(self, key):\n ... return key\n ...\n >>> \'{name} was born in {country}\'.format_map(Default(name=\'Guido\'))\n \'Guido was born in country\'\n\n New in version 3.2.\n\nstr.index(sub[, start[, end]])\n\n Like ``find()``, but raise ``ValueError`` when the substring is not\n found.\n\nstr.isalnum()\n\n Return true if all characters in the string are alphanumeric and\n there is at least one character, false otherwise. A character\n ``c`` is alphanumeric if one of the following returns ``True``:\n ``c.isalpha()``, ``c.isdecimal()``, ``c.isdigit()``, or\n ``c.isnumeric()``.\n\nstr.isalpha()\n\n Return true if all characters in the string are alphabetic and\n there is at least one character, false otherwise. Alphabetic\n characters are those characters defined in the Unicode character\n database as "Letter", i.e., those with general category property\n being one of "Lm", "Lt", "Lu", "Ll", or "Lo". Note that this is\n different from the "Alphabetic" property defined in the Unicode\n Standard.\n\nstr.isdecimal()\n\n Return true if all characters in the string are decimal characters\n and there is at least one character, false otherwise. Decimal\n characters are those from general category "Nd". This category\n includes digit characters, and all characters that that can be used\n to form decimal-radix numbers, e.g. U+0660, ARABIC-INDIC DIGIT\n ZERO.\n\nstr.isdigit()\n\n Return true if all characters in the string are digits and there is\n at least one character, false otherwise. Digits include decimal\n characters and digits that need special handling, such as the\n compatibility superscript digits. Formally, a digit is a character\n that has the property value Numeric_Type=Digit or\n Numeric_Type=Decimal.\n\nstr.isidentifier()\n\n Return true if the string is a valid identifier according to the\n language definition, section *Identifiers and keywords*.\n\nstr.islower()\n\n Return true if all cased characters in the string are lowercase and\n there is at least one cased character, false otherwise. Cased\n characters are those with general category property being one of\n "Lu", "Ll", or "Lt" and lowercase characters are those with general\n category property "Ll".\n\nstr.isnumeric()\n\n Return true if all characters in the string are numeric characters,\n and there is at least one character, false otherwise. Numeric\n characters include digit characters, and all characters that have\n the Unicode numeric value property, e.g. U+2155, VULGAR FRACTION\n ONE FIFTH. Formally, numeric characters are those with the\n property value Numeric_Type=Digit, Numeric_Type=Decimal or\n Numeric_Type=Numeric.\n\nstr.isprintable()\n\n Return true if all characters in the string are printable or the\n string is empty, false otherwise. Nonprintable characters are\n those characters defined in the Unicode character database as\n "Other" or "Separator", excepting the ASCII space (0x20) which is\n considered printable. (Note that printable characters in this\n context are those which should not be escaped when ``repr()`` is\n invoked on a string. It has no bearing on the handling of strings\n written to ``sys.stdout`` or ``sys.stderr``.)\n\nstr.isspace()\n\n Return true if there are only whitespace characters in the string\n and there is at least one character, false otherwise. Whitespace\n characters are those characters defined in the Unicode character\n database as "Other" or "Separator" and those with bidirectional\n property being one of "WS", "B", or "S".\n\nstr.istitle()\n\n Return true if the string is a titlecased string and there is at\n least one character, for example uppercase characters may only\n follow uncased characters and lowercase characters only cased ones.\n Return false otherwise.\n\nstr.isupper()\n\n Return true if all cased characters in the string are uppercase and\n there is at least one cased character, false otherwise. Cased\n characters are those with general category property being one of\n "Lu", "Ll", or "Lt" and uppercase characters are those with general\n category property "Lu".\n\nstr.join(iterable)\n\n Return a string which is the concatenation of the strings in the\n *iterable* *iterable*. A ``TypeError`` will be raised if there are\n any non-string values in *seq*, including ``bytes`` objects. The\n separator between elements is the string providing this method.\n\nstr.ljust(width[, fillchar])\n\n Return the string left justified in a string of length *width*.\n Padding is done using the specified *fillchar* (default is a\n space). The original string is returned if *width* is less than\n ``len(s)``.\n\nstr.lower()\n\n Return a copy of the string converted to lowercase.\n\nstr.lstrip([chars])\n\n Return a copy of the string with leading characters removed. The\n *chars* argument is a string specifying the set of characters to be\n removed. If omitted or ``None``, the *chars* argument defaults to\n removing whitespace. The *chars* argument is not a prefix; rather,\n all combinations of its values are stripped:\n\n >>> \' spacious \'.lstrip()\n \'spacious \'\n >>> \'www.example.com\'.lstrip(\'cmowz.\')\n \'example.com\'\n\nstatic str.maketrans(x[, y[, z]])\n\n This static method returns a translation table usable for\n ``str.translate()``.\n\n If there is only one argument, it must be a dictionary mapping\n Unicode ordinals (integers) or characters (strings of length 1) to\n Unicode ordinals, strings (of arbitrary lengths) or None.\n Character keys will then be converted to ordinals.\n\n If there are two arguments, they must be strings of equal length,\n and in the resulting dictionary, each character in x will be mapped\n to the character at the same position in y. If there is a third\n argument, it must be a string, whose characters will be mapped to\n None in the result.\n\nstr.partition(sep)\n\n Split the string at the first occurrence of *sep*, and return a\n 3-tuple containing the part before the separator, the separator\n itself, and the part after the separator. If the separator is not\n found, return a 3-tuple containing the string itself, followed by\n two empty strings.\n\nstr.replace(old, new[, count])\n\n Return a copy of the string with all occurrences of substring *old*\n replaced by *new*. If the optional argument *count* is given, only\n the first *count* occurrences are replaced.\n\nstr.rfind(sub[, start[, end]])\n\n Return the highest index in the string where substring *sub* is\n found, such that *sub* is contained within ``s[start:end]``.\n Optional arguments *start* and *end* are interpreted as in slice\n notation. Return ``-1`` on failure.\n\nstr.rindex(sub[, start[, end]])\n\n Like ``rfind()`` but raises ``ValueError`` when the substring *sub*\n is not found.\n\nstr.rjust(width[, fillchar])\n\n Return the string right justified in a string of length *width*.\n Padding is done using the specified *fillchar* (default is a\n space). The original string is returned if *width* is less than\n ``len(s)``.\n\nstr.rpartition(sep)\n\n Split the string at the last occurrence of *sep*, and return a\n 3-tuple containing the part before the separator, the separator\n itself, and the part after the separator. If the separator is not\n found, return a 3-tuple containing two empty strings, followed by\n the string itself.\n\nstr.rsplit([sep[, maxsplit]])\n\n Return a list of the words in the string, using *sep* as the\n delimiter string. If *maxsplit* is given, at most *maxsplit* splits\n are done, the *rightmost* ones. If *sep* is not specified or\n ``None``, any whitespace string is a separator. Except for\n splitting from the right, ``rsplit()`` behaves like ``split()``\n which is described in detail below.\n\nstr.rstrip([chars])\n\n Return a copy of the string with trailing characters removed. The\n *chars* argument is a string specifying the set of characters to be\n removed. If omitted or ``None``, the *chars* argument defaults to\n removing whitespace. The *chars* argument is not a suffix; rather,\n all combinations of its values are stripped:\n\n >>> \' spacious \'.rstrip()\n \' spacious\'\n >>> \'mississippi\'.rstrip(\'ipz\')\n \'mississ\'\n\nstr.split([sep[, maxsplit]])\n\n Return a list of the words in the string, using *sep* as the\n delimiter string. If *maxsplit* is given, at most *maxsplit*\n splits are done (thus, the list will have at most ``maxsplit+1``\n elements). If *maxsplit* is not specified, then there is no limit\n on the number of splits (all possible splits are made).\n\n If *sep* is given, consecutive delimiters are not grouped together\n and are deemed to delimit empty strings (for example,\n ``\'1,,2\'.split(\',\')`` returns ``[\'1\', \'\', \'2\']``). The *sep*\n argument may consist of multiple characters (for example,\n ``\'1<>2<>3\'.split(\'<>\')`` returns ``[\'1\', \'2\', \'3\']``). Splitting\n an empty string with a specified separator returns ``[\'\']``.\n\n If *sep* is not specified or is ``None``, a different splitting\n algorithm is applied: runs of consecutive whitespace are regarded\n as a single separator, and the result will contain no empty strings\n at the start or end if the string has leading or trailing\n whitespace. Consequently, splitting an empty string or a string\n consisting of just whitespace with a ``None`` separator returns\n ``[]``.\n\n For example, ``\' 1 2 3 \'.split()`` returns ``[\'1\', \'2\', \'3\']``,\n and ``\' 1 2 3 \'.split(None, 1)`` returns ``[\'1\', \'2 3 \']``.\n\nstr.splitlines([keepends])\n\n Return a list of the lines in the string, breaking at line\n boundaries. Line breaks are not included in the resulting list\n unless *keepends* is given and true.\n\nstr.startswith(prefix[, start[, end]])\n\n Return ``True`` if string starts with the *prefix*, otherwise\n return ``False``. *prefix* can also be a tuple of prefixes to look\n for. With optional *start*, test string beginning at that\n position. With optional *end*, stop comparing string at that\n position.\n\nstr.strip([chars])\n\n Return a copy of the string with the leading and trailing\n characters removed. The *chars* argument is a string specifying the\n set of characters to be removed. If omitted or ``None``, the\n *chars* argument defaults to removing whitespace. The *chars*\n argument is not a prefix or suffix; rather, all combinations of its\n values are stripped:\n\n >>> \' spacious \'.strip()\n \'spacious\'\n >>> \'www.example.com\'.strip(\'cmowz.\')\n \'example\'\n\nstr.swapcase()\n\n Return a copy of the string with uppercase characters converted to\n lowercase and vice versa.\n\nstr.title()\n\n Return a titlecased version of the string where words start with an\n uppercase character and the remaining characters are lowercase.\n\n The algorithm uses a simple language-independent definition of a\n word as groups of consecutive letters. The definition works in\n many contexts but it means that apostrophes in contractions and\n possessives form word boundaries, which may not be the desired\n result:\n\n >>> "they\'re bill\'s friends from the UK".title()\n "They\'Re Bill\'S Friends From The Uk"\n\n A workaround for apostrophes can be constructed using regular\n expressions:\n\n >>> import re\n >>> def titlecase(s):\n return re.sub(r"[A-Za-z]+(\'[A-Za-z]+)?",\n lambda mo: mo.group(0)[0].upper() +\n mo.group(0)[1:].lower(),\n s)\n\n >>> titlecase("they\'re bill\'s friends.")\n "They\'re Bill\'s Friends."\n\nstr.translate(map)\n\n Return a copy of the *s* where all characters have been mapped\n through the *map* which must be a dictionary of Unicode ordinals\n (integers) to Unicode ordinals, strings or ``None``. Unmapped\n characters are left untouched. Characters mapped to ``None`` are\n deleted.\n\n You can use ``str.maketrans()`` to create a translation map from\n character-to-character mappings in different formats.\n\n Note: An even more flexible approach is to create a custom character\n mapping codec using the ``codecs`` module (see\n ``encodings.cp1251`` for an example).\n\nstr.upper()\n\n Return a copy of the string converted to uppercase.\n\nstr.zfill(width)\n\n Return the numeric string left filled with zeros in a string of\n length *width*. A sign prefix is handled correctly. The original\n string is returned if *width* is less than ``len(s)``.\n', 'strings': '\nString and Bytes literals\n*************************\n\nString literals are described by the following lexical definitions:\n\n stringliteral ::= [stringprefix](shortstring | longstring)\n stringprefix ::= "r" | "R"\n shortstring ::= "\'" shortstringitem* "\'" | \'"\' shortstringitem* \'"\'\n longstring ::= "\'\'\'" longstringitem* "\'\'\'" | \'"""\' longstringitem* \'"""\'\n shortstringitem ::= shortstringchar | stringescapeseq\n longstringitem ::= longstringchar | stringescapeseq\n shortstringchar ::= \n longstringchar ::= \n stringescapeseq ::= "\\" \n\n bytesliteral ::= bytesprefix(shortbytes | longbytes)\n bytesprefix ::= "b" | "B" | "br" | "Br" | "bR" | "BR"\n shortbytes ::= "\'" shortbytesitem* "\'" | \'"\' shortbytesitem* \'"\'\n longbytes ::= "\'\'\'" longbytesitem* "\'\'\'" | \'"""\' longbytesitem* \'"""\'\n shortbytesitem ::= shortbyteschar | bytesescapeseq\n longbytesitem ::= longbyteschar | bytesescapeseq\n shortbyteschar ::= \n longbyteschar ::= \n bytesescapeseq ::= "\\" \n\nOne syntactic restriction not indicated by these productions is that\nwhitespace is not allowed between the ``stringprefix`` or\n``bytesprefix`` and the rest of the literal. The source character set\nis defined by the encoding declaration; it is UTF-8 if no encoding\ndeclaration is given in the source file; see section *Encoding\ndeclarations*.\n\nIn plain English: Both types of literals can be enclosed in matching\nsingle quotes (``\'``) or double quotes (``"``). They can also be\nenclosed in matching groups of three single or double quotes (these\nare generally referred to as *triple-quoted strings*). The backslash\n(``\\``) character is used to escape characters that otherwise have a\nspecial meaning, such as newline, backslash itself, or the quote\ncharacter.\n\nBytes literals are always prefixed with ``\'b\'`` or ``\'B\'``; they\nproduce an instance of the ``bytes`` type instead of the ``str`` type.\nThey may only contain ASCII characters; bytes with a numeric value of\n128 or greater must be expressed with escapes.\n\nBoth string and bytes literals may optionally be prefixed with a\nletter ``\'r\'`` or ``\'R\'``; such strings are called *raw strings* and\ntreat backslashes as literal characters. As a result, in string\nliterals, ``\'\\U\'`` and ``\'\\u\'`` escapes in raw strings are not treated\nspecially.\n\nIn triple-quoted strings, unescaped newlines and quotes are allowed\n(and are retained), except that three unescaped quotes in a row\nterminate the string. (A "quote" is the character used to open the\nstring, i.e. either ``\'`` or ``"``.)\n\nUnless an ``\'r\'`` or ``\'R\'`` prefix is present, escape sequences in\nstrings are interpreted according to rules similar to those used by\nStandard C. The recognized escape sequences are:\n\n+-------------------+-----------------------------------+---------+\n| Escape Sequence | Meaning | Notes |\n+===================+===================================+=========+\n| ``\\newline`` | Backslash and newline ignored | |\n+-------------------+-----------------------------------+---------+\n| ``\\\\`` | Backslash (``\\``) | |\n+-------------------+-----------------------------------+---------+\n| ``\\\'`` | Single quote (``\'``) | |\n+-------------------+-----------------------------------+---------+\n| ``\\"`` | Double quote (``"``) | |\n+-------------------+-----------------------------------+---------+\n| ``\\a`` | ASCII Bell (BEL) | |\n+-------------------+-----------------------------------+---------+\n| ``\\b`` | ASCII Backspace (BS) | |\n+-------------------+-----------------------------------+---------+\n| ``\\f`` | ASCII Formfeed (FF) | |\n+-------------------+-----------------------------------+---------+\n| ``\\n`` | ASCII Linefeed (LF) | |\n+-------------------+-----------------------------------+---------+\n| ``\\r`` | ASCII Carriage Return (CR) | |\n+-------------------+-----------------------------------+---------+\n| ``\\t`` | ASCII Horizontal Tab (TAB) | |\n+-------------------+-----------------------------------+---------+\n| ``\\v`` | ASCII Vertical Tab (VT) | |\n+-------------------+-----------------------------------+---------+\n| ``\\ooo`` | Character with octal value *ooo* | (1,3) |\n+-------------------+-----------------------------------+---------+\n| ``\\xhh`` | Character with hex value *hh* | (2,3) |\n+-------------------+-----------------------------------+---------+\n\nEscape sequences only recognized in string literals are:\n\n+-------------------+-----------------------------------+---------+\n| Escape Sequence | Meaning | Notes |\n+===================+===================================+=========+\n| ``\\N{name}`` | Character named *name* in the | |\n| | Unicode database | |\n+-------------------+-----------------------------------+---------+\n| ``\\uxxxx`` | Character with 16-bit hex value | (4) |\n| | *xxxx* | |\n+-------------------+-----------------------------------+---------+\n| ``\\Uxxxxxxxx`` | Character with 32-bit hex value | (5) |\n| | *xxxxxxxx* | |\n+-------------------+-----------------------------------+---------+\n\nNotes:\n\n1. As in Standard C, up to three octal digits are accepted.\n\n2. Unlike in Standard C, exactly two hex digits are required.\n\n3. In a bytes literal, hexadecimal and octal escapes denote the byte\n with the given value. In a string literal, these escapes denote a\n Unicode character with the given value.\n\n4. Individual code units which form parts of a surrogate pair can be\n encoded using this escape sequence. Exactly four hex digits are\n required.\n\n5. Any Unicode character can be encoded this way, but characters\n outside the Basic Multilingual Plane (BMP) will be encoded using a\n surrogate pair if Python is compiled to use 16-bit code units (the\n default). Exactly eight hex digits are required.\n\nUnlike Standard C, all unrecognized escape sequences are left in the\nstring unchanged, i.e., *the backslash is left in the string*. (This\nbehavior is useful when debugging: if an escape sequence is mistyped,\nthe resulting output is more easily recognized as broken.) It is also\nimportant to note that the escape sequences only recognized in string\nliterals fall into the category of unrecognized escapes for bytes\nliterals.\n\nEven in a raw string, string quotes can be escaped with a backslash,\nbut the backslash remains in the string; for example, ``r"\\""`` is a\nvalid string literal consisting of two characters: a backslash and a\ndouble quote; ``r"\\"`` is not a valid string literal (even a raw\nstring cannot end in an odd number of backslashes). Specifically, *a\nraw string cannot end in a single backslash* (since the backslash\nwould escape the following quote character). Note also that a single\nbackslash followed by a newline is interpreted as those two characters\nas part of the string, *not* as a line continuation.\n', 'subscriptions': '\nSubscriptions\n*************\n\nA subscription selects an item of a sequence (string, tuple or list)\nor mapping (dictionary) object:\n\n subscription ::= primary "[" expression_list "]"\n\nThe primary must evaluate to an object that supports subscription,\ne.g. a list or dictionary. User-defined objects can support\nsubscription by defining a ``__getitem__()`` method.\n\nFor built-in objects, there are two types of objects that support\nsubscription:\n\nIf the primary is a mapping, the expression list must evaluate to an\nobject whose value is one of the keys of the mapping, and the\nsubscription selects the value in the mapping that corresponds to that\nkey. (The expression list is a tuple except if it has exactly one\nitem.)\n\nIf the primary is a sequence, the expression (list) must evaluate to\nan integer or a slice (as discussed in the following section).\n\nThe formal syntax makes no special provision for negative indices in\nsequences; however, built-in sequences all provide a ``__getitem__()``\nmethod that interprets negative indices by adding the length of the\nsequence to the index (so that ``x[-1]`` selects the last item of\n``x``). The resulting value must be a nonnegative integer less than\nthe number of items in the sequence, and the subscription selects the\nitem whose index is that value (counting from zero). Since the support\nfor negative indices and slicing occurs in the object\'s\n``__getitem__()`` method, subclasses overriding this method will need\nto explicitly add that support.\n\nA string\'s items are characters. A character is not a separate data\ntype but a string of exactly one character.\n', @@ -70,8 +70,8 @@ 'typesmapping': '\nMapping Types --- ``dict``\n**************************\n\nA *mapping* object maps *hashable* values to arbitrary objects.\nMappings are mutable objects. There is currently only one standard\nmapping type, the *dictionary*. (For other containers see the built\nin ``list``, ``set``, and ``tuple`` classes, and the ``collections``\nmodule.)\n\nA dictionary\'s keys are *almost* arbitrary values. Values that are\nnot *hashable*, that is, values containing lists, dictionaries or\nother mutable types (that are compared by value rather than by object\nidentity) may not be used as keys. Numeric types used for keys obey\nthe normal rules for numeric comparison: if two numbers compare equal\n(such as ``1`` and ``1.0``) then they can be used interchangeably to\nindex the same dictionary entry. (Note however, that since computers\nstore floating-point numbers as approximations it is usually unwise to\nuse them as dictionary keys.)\n\nDictionaries can be created by placing a comma-separated list of\n``key: value`` pairs within braces, for example: ``{\'jack\': 4098,\n\'sjoerd\': 4127}`` or ``{4098: \'jack\', 4127: \'sjoerd\'}``, or by the\n``dict`` constructor.\n\nclass class dict([arg])\n\n Return a new dictionary initialized from an optional positional\n argument or from a set of keyword arguments. If no arguments are\n given, return a new empty dictionary. If the positional argument\n *arg* is a mapping object, return a dictionary mapping the same\n keys to the same values as does the mapping object. Otherwise the\n positional argument must be a sequence, a container that supports\n iteration, or an iterator object. The elements of the argument\n must each also be of one of those kinds, and each must in turn\n contain exactly two objects. The first is used as a key in the new\n dictionary, and the second as the key\'s value. If a given key is\n seen more than once, the last value associated with it is retained\n in the new dictionary.\n\n If keyword arguments are given, the keywords themselves with their\n associated values are added as items to the dictionary. If a key\n is specified both in the positional argument and as a keyword\n argument, the value associated with the keyword is retained in the\n dictionary. For example, these all return a dictionary equal to\n ``{"one": 1, "two": 2}``:\n\n * ``dict(one=1, two=2)``\n\n * ``dict({\'one\': 1, \'two\': 2})``\n\n * ``dict(zip((\'one\', \'two\'), (1, 2)))``\n\n * ``dict([[\'two\', 2], [\'one\', 1]])``\n\n The first example only works for keys that are valid Python\n identifiers; the others work with any valid keys.\n\n These are the operations that dictionaries support (and therefore,\n custom mapping types should support too):\n\n len(d)\n\n Return the number of items in the dictionary *d*.\n\n d[key]\n\n Return the item of *d* with key *key*. Raises a ``KeyError`` if\n *key* is not in the map.\n\n If a subclass of dict defines a method ``__missing__()``, if the\n key *key* is not present, the ``d[key]`` operation calls that\n method with the key *key* as argument. The ``d[key]`` operation\n then returns or raises whatever is returned or raised by the\n ``__missing__(key)`` call if the key is not present. No other\n operations or methods invoke ``__missing__()``. If\n ``__missing__()`` is not defined, ``KeyError`` is raised.\n ``__missing__()`` must be a method; it cannot be an instance\n variable:\n\n >>> class Counter(dict):\n ... def __missing__(self, key):\n ... return 0\n >>> c = Counter()\n >>> c[\'red\']\n 0\n >>> c[\'red\'] += 1\n >>> c[\'red\']\n 1\n\n See ``collections.Counter`` for a complete implementation\n including other methods helpful for accumulating and managing\n tallies.\n\n d[key] = value\n\n Set ``d[key]`` to *value*.\n\n del d[key]\n\n Remove ``d[key]`` from *d*. Raises a ``KeyError`` if *key* is\n not in the map.\n\n key in d\n\n Return ``True`` if *d* has a key *key*, else ``False``.\n\n key not in d\n\n Equivalent to ``not key in d``.\n\n iter(d)\n\n Return an iterator over the keys of the dictionary. This is a\n shortcut for ``iter(d.keys())``.\n\n clear()\n\n Remove all items from the dictionary.\n\n copy()\n\n Return a shallow copy of the dictionary.\n\n classmethod fromkeys(seq[, value])\n\n Create a new dictionary with keys from *seq* and values set to\n *value*.\n\n ``fromkeys()`` is a class method that returns a new dictionary.\n *value* defaults to ``None``.\n\n get(key[, default])\n\n Return the value for *key* if *key* is in the dictionary, else\n *default*. If *default* is not given, it defaults to ``None``,\n so that this method never raises a ``KeyError``.\n\n items()\n\n Return a new view of the dictionary\'s items (``(key, value)``\n pairs). See below for documentation of view objects.\n\n keys()\n\n Return a new view of the dictionary\'s keys. See below for\n documentation of view objects.\n\n pop(key[, default])\n\n If *key* is in the dictionary, remove it and return its value,\n else return *default*. If *default* is not given and *key* is\n not in the dictionary, a ``KeyError`` is raised.\n\n popitem()\n\n Remove and return an arbitrary ``(key, value)`` pair from the\n dictionary.\n\n ``popitem()`` is useful to destructively iterate over a\n dictionary, as often used in set algorithms. If the dictionary\n is empty, calling ``popitem()`` raises a ``KeyError``.\n\n setdefault(key[, default])\n\n If *key* is in the dictionary, return its value. If not, insert\n *key* with a value of *default* and return *default*. *default*\n defaults to ``None``.\n\n update([other])\n\n Update the dictionary with the key/value pairs from *other*,\n overwriting existing keys. Return ``None``.\n\n ``update()`` accepts either another dictionary object or an\n iterable of key/value pairs (as tuples or other iterables of\n length two). If keyword arguments are specified, the dictionary\n is then updated with those key/value pairs: ``d.update(red=1,\n blue=2)``.\n\n values()\n\n Return a new view of the dictionary\'s values. See below for\n documentation of view objects.\n\n\nDictionary view objects\n=======================\n\nThe objects returned by ``dict.keys()``, ``dict.values()`` and\n``dict.items()`` are *view objects*. They provide a dynamic view on\nthe dictionary\'s entries, which means that when the dictionary\nchanges, the view reflects these changes.\n\nDictionary views can be iterated over to yield their respective data,\nand support membership tests:\n\nlen(dictview)\n\n Return the number of entries in the dictionary.\n\niter(dictview)\n\n Return an iterator over the keys, values or items (represented as\n tuples of ``(key, value)``) in the dictionary.\n\n Keys and values are iterated over in an arbitrary order which is\n non-random, varies across Python implementations, and depends on\n the dictionary\'s history of insertions and deletions. If keys,\n values and items views are iterated over with no intervening\n modifications to the dictionary, the order of items will directly\n correspond. This allows the creation of ``(value, key)`` pairs\n using ``zip()``: ``pairs = zip(d.values(), d.keys())``. Another\n way to create the same list is ``pairs = [(v, k) for (k, v) in\n d.items()]``.\n\n Iterating views while adding or deleting entries in the dictionary\n may raise a ``RuntimeError`` or fail to iterate over all entries.\n\nx in dictview\n\n Return ``True`` if *x* is in the underlying dictionary\'s keys,\n values or items (in the latter case, *x* should be a ``(key,\n value)`` tuple).\n\nKeys views are set-like since their entries are unique and hashable.\nIf all values are hashable, so that ``(key, value)`` pairs are unique\nand hashable, then the items view is also set-like. (Values views are\nnot treated as set-like since the entries are generally not unique.)\nFor set-like views, all of the operations defined for the abstract\nbase class ``collections.Set`` are available (for example, ``==``,\n``<``, or ``^``).\n\nAn example of dictionary view usage:\n\n >>> dishes = {\'eggs\': 2, \'sausage\': 1, \'bacon\': 1, \'spam\': 500}\n >>> keys = dishes.keys()\n >>> values = dishes.values()\n\n >>> # iteration\n >>> n = 0\n >>> for val in values:\n ... n += val\n >>> print(n)\n 504\n\n >>> # keys and values are iterated over in the same order\n >>> list(keys)\n [\'eggs\', \'bacon\', \'sausage\', \'spam\']\n >>> list(values)\n [2, 1, 1, 500]\n\n >>> # view objects are dynamic and reflect dict changes\n >>> del dishes[\'eggs\']\n >>> del dishes[\'sausage\']\n >>> list(keys)\n [\'spam\', \'bacon\']\n\n >>> # set operations\n >>> keys & {\'eggs\', \'bacon\', \'salad\'}\n {\'bacon\'}\n >>> keys ^ {\'sausage\', \'juice\'}\n {\'juice\', \'eggs\', \'bacon\', \'spam\'}\n', 'typesmethods': "\nMethods\n*******\n\nMethods are functions that are called using the attribute notation.\nThere are two flavors: built-in methods (such as ``append()`` on\nlists) and class instance methods. Built-in methods are described\nwith the types that support them.\n\nIf you access a method (a function defined in a class namespace)\nthrough an instance, you get a special object: a *bound method* (also\ncalled *instance method*) object. When called, it will add the\n``self`` argument to the argument list. Bound methods have two\nspecial read-only attributes: ``m.__self__`` is the object on which\nthe method operates, and ``m.__func__`` is the function implementing\nthe method. Calling ``m(arg-1, arg-2, ..., arg-n)`` is completely\nequivalent to calling ``m.__func__(m.__self__, arg-1, arg-2, ...,\narg-n)``.\n\nLike function objects, bound method objects support getting arbitrary\nattributes. However, since method attributes are actually stored on\nthe underlying function object (``meth.__func__``), setting method\nattributes on bound methods is disallowed. Attempting to set a method\nattribute results in a ``TypeError`` being raised. In order to set a\nmethod attribute, you need to explicitly set it on the underlying\nfunction object:\n\n class C:\n def method(self):\n pass\n\n c = C()\n c.method.__func__.whoami = 'my name is c'\n\nSee *The standard type hierarchy* for more information.\n", 'typesmodules': "\nModules\n*******\n\nThe only special operation on a module is attribute access:\n``m.name``, where *m* is a module and *name* accesses a name defined\nin *m*'s symbol table. Module attributes can be assigned to. (Note\nthat the ``import`` statement is not, strictly speaking, an operation\non a module object; ``import foo`` does not require a module object\nnamed *foo* to exist, rather it requires an (external) *definition*\nfor a module named *foo* somewhere.)\n\nA special member of every module is ``__dict__``. This is the\ndictionary containing the module's symbol table. Modifying this\ndictionary will actually change the module's symbol table, but direct\nassignment to the ``__dict__`` attribute is not possible (you can\nwrite ``m.__dict__['a'] = 1``, which defines ``m.a`` to be ``1``, but\nyou can't write ``m.__dict__ = {}``). Modifying ``__dict__`` directly\nis not recommended.\n\nModules built into the interpreter are written like this: ````. If loaded from a file, they are written as\n````.\n", - 'typesseq': '\nSequence Types --- ``str``, ``bytes``, ``bytearray``, ``list``, ``tuple``, ``range``\n************************************************************************************\n\nThere are six sequence types: strings, byte sequences (``bytes``\nobjects), byte arrays (``bytearray`` objects), lists, tuples, and\nrange objects. For other containers see the built in ``dict`` and\n``set`` classes, and the ``collections`` module.\n\nStrings contain Unicode characters. Their literals are written in\nsingle or double quotes: ``\'xyzzy\'``, ``"frobozz"``. See *String and\nBytes literals* for more about string literals. In addition to the\nfunctionality described here, there are also string-specific methods\ndescribed in the *String Methods* section.\n\nBytes and bytearray objects contain single bytes -- the former is\nimmutable while the latter is a mutable sequence. Bytes objects can\nbe constructed the constructor, ``bytes()``, and from literals; use a\n``b`` prefix with normal string syntax: ``b\'xyzzy\'``. To construct\nbyte arrays, use the ``bytearray()`` function.\n\nWhile string objects are sequences of characters (represented by\nstrings of length 1), bytes and bytearray objects are sequences of\n*integers* (between 0 and 255), representing the ASCII value of single\nbytes. That means that for a bytes or bytearray object *b*, ``b[0]``\nwill be an integer, while ``b[0:1]`` will be a bytes or bytearray\nobject of length 1. The representation of bytes objects uses the\nliteral format (``b\'...\'``) since it is generally more useful than\ne.g. ``bytes([50, 19, 100])``. You can always convert a bytes object\ninto a list of integers using ``list(b)``.\n\nAlso, while in previous Python versions, byte strings and Unicode\nstrings could be exchanged for each other rather freely (barring\nencoding issues), strings and bytes are now completely separate\nconcepts. There\'s no implicit en-/decoding if you pass an object of\nthe wrong type. A string always compares unequal to a bytes or\nbytearray object.\n\nLists are constructed with square brackets, separating items with\ncommas: ``[a, b, c]``. Tuples are constructed by the comma operator\n(not within square brackets), with or without enclosing parentheses,\nbut an empty tuple must have the enclosing parentheses, such as ``a,\nb, c`` or ``()``. A single item tuple must have a trailing comma,\nsuch as ``(d,)``.\n\nObjects of type range are created using the ``range()`` function.\nThey don\'t support concatenation or repetition, and using ``min()`` or\n``max()`` on them is inefficient.\n\nMost sequence types support the following operations. The ``in`` and\n``not in`` operations have the same priorities as the comparison\noperations. The ``+`` and ``*`` operations have the same priority as\nthe corresponding numeric operations. [3] Additional methods are\nprovided for *Mutable Sequence Types*.\n\nThis table lists the sequence operations sorted in ascending priority\n(operations in the same box have the same priority). In the table,\n*s* and *t* are sequences of the same type; *n*, *i*, *j* and *k* are\nintegers.\n\n+--------------------+----------------------------------+------------+\n| Operation | Result | Notes |\n+====================+==================================+============+\n| ``x in s`` | ``True`` if an item of *s* is | (1) |\n| | equal to *x*, else ``False`` | |\n+--------------------+----------------------------------+------------+\n| ``x not in s`` | ``False`` if an item of *s* is | (1) |\n| | equal to *x*, else ``True`` | |\n+--------------------+----------------------------------+------------+\n| ``s + t`` | the concatenation of *s* and *t* | (6) |\n+--------------------+----------------------------------+------------+\n| ``s * n, n * s`` | *n* shallow copies of *s* | (2) |\n| | concatenated | |\n+--------------------+----------------------------------+------------+\n| ``s[i]`` | *i*\'th item of *s*, origin 0 | (3) |\n+--------------------+----------------------------------+------------+\n| ``s[i:j]`` | slice of *s* from *i* to *j* | (3)(4) |\n+--------------------+----------------------------------+------------+\n| ``s[i:j:k]`` | slice of *s* from *i* to *j* | (3)(5) |\n| | with step *k* | |\n+--------------------+----------------------------------+------------+\n| ``len(s)`` | length of *s* | |\n+--------------------+----------------------------------+------------+\n| ``min(s)`` | smallest item of *s* | |\n+--------------------+----------------------------------+------------+\n| ``max(s)`` | largest item of *s* | |\n+--------------------+----------------------------------+------------+\n| ``s.index(i)`` | index of the first occurence of | |\n| | *i* in *s* | |\n+--------------------+----------------------------------+------------+\n| ``s.count(i)`` | total number of occurences of | |\n| | *i* in *s* | |\n+--------------------+----------------------------------+------------+\n\nSequence types also support comparisons. In particular, tuples and\nlists are compared lexicographically by comparing corresponding\nelements. This means that to compare equal, every element must\ncompare equal and the two sequences must be of the same type and have\nthe same length. (For full details see *Comparisons* in the language\nreference.)\n\nNotes:\n\n1. When *s* is a string object, the ``in`` and ``not in`` operations\n act like a substring test.\n\n2. Values of *n* less than ``0`` are treated as ``0`` (which yields an\n empty sequence of the same type as *s*). Note also that the copies\n are shallow; nested structures are not copied. This often haunts\n new Python programmers; consider:\n\n >>> lists = [[]] * 3\n >>> lists\n [[], [], []]\n >>> lists[0].append(3)\n >>> lists\n [[3], [3], [3]]\n\n What has happened is that ``[[]]`` is a one-element list containing\n an empty list, so all three elements of ``[[]] * 3`` are (pointers\n to) this single empty list. Modifying any of the elements of\n ``lists`` modifies this single list. You can create a list of\n different lists this way:\n\n >>> lists = [[] for i in range(3)]\n >>> lists[0].append(3)\n >>> lists[1].append(5)\n >>> lists[2].append(7)\n >>> lists\n [[3], [5], [7]]\n\n3. If *i* or *j* is negative, the index is relative to the end of the\n string: ``len(s) + i`` or ``len(s) + j`` is substituted. But note\n that ``-0`` is still ``0``.\n\n4. The slice of *s* from *i* to *j* is defined as the sequence of\n items with index *k* such that ``i <= k < j``. If *i* or *j* is\n greater than ``len(s)``, use ``len(s)``. If *i* is omitted or\n ``None``, use ``0``. If *j* is omitted or ``None``, use\n ``len(s)``. If *i* is greater than or equal to *j*, the slice is\n empty.\n\n5. The slice of *s* from *i* to *j* with step *k* is defined as the\n sequence of items with index ``x = i + n*k`` such that ``0 <= n <\n (j-i)/k``. In other words, the indices are ``i``, ``i+k``,\n ``i+2*k``, ``i+3*k`` and so on, stopping when *j* is reached (but\n never including *j*). If *i* or *j* is greater than ``len(s)``,\n use ``len(s)``. If *i* or *j* are omitted or ``None``, they become\n "end" values (which end depends on the sign of *k*). Note, *k*\n cannot be zero. If *k* is ``None``, it is treated like ``1``.\n\n6. **CPython implementation detail:** If *s* and *t* are both strings,\n some Python implementations such as CPython can usually perform an\n in-place optimization for assignments of the form ``s = s + t`` or\n ``s += t``. When applicable, this optimization makes quadratic\n run-time much less likely. This optimization is both version and\n implementation dependent. For performance sensitive code, it is\n preferable to use the ``str.join()`` method which assures\n consistent linear concatenation performance across versions and\n implementations.\n\n\nString Methods\n==============\n\nString objects support the methods listed below.\n\nIn addition, Python\'s strings support the sequence type methods\ndescribed in the *Sequence Types --- str, bytes, bytearray, list,\ntuple, range* section. To output formatted strings, see the *String\nFormatting* section. Also, see the ``re`` module for string functions\nbased on regular expressions.\n\nstr.capitalize()\n\n Return a copy of the string with its first character capitalized\n and the rest lowercased.\n\nstr.center(width[, fillchar])\n\n Return centered in a string of length *width*. Padding is done\n using the specified *fillchar* (default is a space).\n\nstr.count(sub[, start[, end]])\n\n Return the number of non-overlapping occurrences of substring *sub*\n in the range [*start*, *end*]. Optional arguments *start* and\n *end* are interpreted as in slice notation.\n\nstr.encode(encoding="utf-8", errors="strict")\n\n Return an encoded version of the string as a bytes object. Default\n encoding is ``\'utf-8\'``. *errors* may be given to set a different\n error handling scheme. The default for *errors* is ``\'strict\'``,\n meaning that encoding errors raise a ``UnicodeError``. Other\n possible values are ``\'ignore\'``, ``\'replace\'``,\n ``\'xmlcharrefreplace\'``, ``\'backslashreplace\'`` and any other name\n registered via ``codecs.register_error()``, see section *Codec Base\n Classes*. For a list of possible encodings, see section *Standard\n Encodings*.\n\n Changed in version 3.1: Support for keyword arguments added.\n\nstr.endswith(suffix[, start[, end]])\n\n Return ``True`` if the string ends with the specified *suffix*,\n otherwise return ``False``. *suffix* can also be a tuple of\n suffixes to look for. With optional *start*, test beginning at\n that position. With optional *end*, stop comparing at that\n position.\n\nstr.expandtabs([tabsize])\n\n Return a copy of the string where all tab characters are replaced\n by one or more spaces, depending on the current column and the\n given tab size. The column number is reset to zero after each\n newline occurring in the string. If *tabsize* is not given, a tab\n size of ``8`` characters is assumed. This doesn\'t understand other\n non-printing characters or escape sequences.\n\nstr.find(sub[, start[, end]])\n\n Return the lowest index in the string where substring *sub* is\n found, such that *sub* is contained in the slice ``s[start:end]``.\n Optional arguments *start* and *end* are interpreted as in slice\n notation. Return ``-1`` if *sub* is not found.\n\nstr.format(*args, **kwargs)\n\n Perform a string formatting operation. The string on which this\n method is called can contain literal text or replacement fields\n delimited by braces ``{}``. Each replacement field contains either\n the numeric index of a positional argument, or the name of a\n keyword argument. Returns a copy of the string where each\n replacement field is replaced with the string value of the\n corresponding argument.\n\n >>> "The sum of 1 + 2 is {0}".format(1+2)\n \'The sum of 1 + 2 is 3\'\n\n See *Format String Syntax* for a description of the various\n formatting options that can be specified in format strings.\n\nstr.format_map(mapping)\n\n Similar to ``str.format(**mapping)``, except that ``mapping`` is\n used directly and not copied to a ``dict`` . This is useful if for\n example ``mapping`` is a dict subclass:\n\n >>> class Default(dict):\n ... def __missing__(self, key):\n ... return key\n ...\n >>> \'{name} was born in {country}\'.format_map(Default(name=\'Guido\'))\n \'Guido was born in country\'\n\n New in version 3.2.\n\nstr.index(sub[, start[, end]])\n\n Like ``find()``, but raise ``ValueError`` when the substring is not\n found.\n\nstr.isalnum()\n\n Return true if all characters in the string are alphanumeric and\n there is at least one character, false otherwise. A character\n ``c`` is alphanumeric if one of the following returns ``True``:\n ``c.isalpha()``, ``c.isdecimal()``, ``c.isdigit()``, or\n ``c.isnumeric()``.\n\nstr.isalpha()\n\n Return true if all characters in the string are alphabetic and\n there is at least one character, false otherwise. Alphabetic\n characters are those characters defined in the Unicode character\n database as "Letter", i.e., those with general category property\n being one of "Lm", "Lt", "Lu", "Ll", or "Lo". Note that this is\n different from the "Alphabetic" property defined in the Unicode\n Standard.\n\nstr.isdecimal()\n\n Return true if all characters in the string are decimal characters\n and there is at least one character, false otherwise. Decimal\n characters are those from general category "Nd". This category\n includes digit characters, and all characters that that can be used\n to form decimal-radix numbers, e.g. U+0660, ARABIC-INDIC DIGIT\n ZERO.\n\nstr.isdigit()\n\n Return true if all characters in the string are digits and there is\n at least one character, false otherwise. Digits include decimal\n characters and digits that need special handling, such as the\n compatibility superscript digits. Formally, a digit is a character\n that has the property value Numeric_Type=Digit or\n Numeric_Type=Decimal.\n\nstr.isidentifier()\n\n Return true if the string is a valid identifier according to the\n language definition, section *Identifiers and keywords*.\n\nstr.islower()\n\n Return true if all cased characters in the string are lowercase and\n there is at least one cased character, false otherwise. Cased\n characters are those with general category property being one of\n "Lu", "Ll", or "Lt" and lowercase characters are those with general\n category property "Ll".\n\nstr.isnumeric()\n\n Return true if all characters in the string are numeric characters,\n and there is at least one character, false otherwise. Numeric\n characters include digit characters, and all characters that have\n the Unicode numeric value property, e.g. U+2155, VULGAR FRACTION\n ONE FIFTH. Formally, numeric characters are those with the\n property value Numeric_Type=Digit, Numeric_Type=Decimal or\n Numeric_Type=Numeric.\n\nstr.isprintable()\n\n Return true if all characters in the string are printable or the\n string is empty, false otherwise. Nonprintable characters are\n those characters defined in the Unicode character database as\n "Other" or "Separator", excepting the ASCII space (0x20) which is\n considered printable. (Note that printable characters in this\n context are those which should not be escaped when ``repr()`` is\n invoked on a string. It has no bearing on the handling of strings\n written to ``sys.stdout`` or ``sys.stderr``.)\n\nstr.isspace()\n\n Return true if there are only whitespace characters in the string\n and there is at least one character, false otherwise. Whitespace\n characters are those characters defined in the Unicode character\n database as "Other" or "Separator" and those with bidirectional\n property being one of "WS", "B", or "S".\n\nstr.istitle()\n\n Return true if the string is a titlecased string and there is at\n least one character, for example uppercase characters may only\n follow uncased characters and lowercase characters only cased ones.\n Return false otherwise.\n\nstr.isupper()\n\n Return true if all cased characters in the string are uppercase and\n there is at least one cased character, false otherwise. Cased\n characters are those with general category property being one of\n "Lu", "Ll", or "Lt" and uppercase characters are those with general\n category property "Lu".\n\nstr.join(iterable)\n\n Return a string which is the concatenation of the strings in the\n *iterable* *iterable*. A ``TypeError`` will be raised if there are\n any non-string values in *seq*, including ``bytes`` objects. The\n separator between elements is the string providing this method.\n\nstr.ljust(width[, fillchar])\n\n Return the string left justified in a string of length *width*.\n Padding is done using the specified *fillchar* (default is a\n space). The original string is returned if *width* is less than\n ``len(s)``.\n\nstr.lower()\n\n Return a copy of the string converted to lowercase.\n\nstr.lstrip([chars])\n\n Return a copy of the string with leading characters removed. The\n *chars* argument is a string specifying the set of characters to be\n removed. If omitted or ``None``, the *chars* argument defaults to\n removing whitespace. The *chars* argument is not a prefix; rather,\n all combinations of its values are stripped:\n\n >>> \' spacious \'.lstrip()\n \'spacious \'\n >>> \'www.example.com\'.lstrip(\'cmowz.\')\n \'example.com\'\n\nstatic str.maketrans(x[, y[, z]])\n\n This static method returns a translation table usable for\n ``str.translate()``.\n\n If there is only one argument, it must be a dictionary mapping\n Unicode ordinals (integers) or characters (strings of length 1) to\n Unicode ordinals, strings (of arbitrary lengths) or None.\n Character keys will then be converted to ordinals.\n\n If there are two arguments, they must be strings of equal length,\n and in the resulting dictionary, each character in x will be mapped\n to the character at the same position in y. If there is a third\n argument, it must be a string, whose characters will be mapped to\n None in the result.\n\nstr.partition(sep)\n\n Split the string at the first occurrence of *sep*, and return a\n 3-tuple containing the part before the separator, the separator\n itself, and the part after the separator. If the separator is not\n found, return a 3-tuple containing the string itself, followed by\n two empty strings.\n\nstr.replace(old, new[, count])\n\n Return a copy of the string with all occurrences of substring *old*\n replaced by *new*. If the optional argument *count* is given, only\n the first *count* occurrences are replaced.\n\nstr.rfind(sub[, start[, end]])\n\n Return the highest index in the string where substring *sub* is\n found, such that *sub* is contained within ``s[start:end]``.\n Optional arguments *start* and *end* are interpreted as in slice\n notation. Return ``-1`` on failure.\n\nstr.rindex(sub[, start[, end]])\n\n Like ``rfind()`` but raises ``ValueError`` when the substring *sub*\n is not found.\n\nstr.rjust(width[, fillchar])\n\n Return the string right justified in a string of length *width*.\n Padding is done using the specified *fillchar* (default is a\n space). The original string is returned if *width* is less than\n ``len(s)``.\n\nstr.rpartition(sep)\n\n Split the string at the last occurrence of *sep*, and return a\n 3-tuple containing the part before the separator, the separator\n itself, and the part after the separator. If the separator is not\n found, return a 3-tuple containing two empty strings, followed by\n the string itself.\n\nstr.rsplit([sep[, maxsplit]])\n\n Return a list of the words in the string, using *sep* as the\n delimiter string. If *maxsplit* is given, at most *maxsplit* splits\n are done, the *rightmost* ones. If *sep* is not specified or\n ``None``, any whitespace string is a separator. Except for\n splitting from the right, ``rsplit()`` behaves like ``split()``\n which is described in detail below.\n\nstr.rstrip([chars])\n\n Return a copy of the string with trailing characters removed. The\n *chars* argument is a string specifying the set of characters to be\n removed. If omitted or ``None``, the *chars* argument defaults to\n removing whitespace. The *chars* argument is not a suffix; rather,\n all combinations of its values are stripped:\n\n >>> \' spacious \'.rstrip()\n \' spacious\'\n >>> \'mississippi\'.rstrip(\'ipz\')\n \'mississ\'\n\nstr.split([sep[, maxsplit]])\n\n Return a list of the words in the string, using *sep* as the\n delimiter string. If *maxsplit* is given, at most *maxsplit*\n splits are done (thus, the list will have at most ``maxsplit+1``\n elements). If *maxsplit* is not specified, then there is no limit\n on the number of splits (all possible splits are made).\n\n If *sep* is given, consecutive delimiters are not grouped together\n and are deemed to delimit empty strings (for example,\n ``\'1,,2\'.split(\',\')`` returns ``[\'1\', \'\', \'2\']``). The *sep*\n argument may consist of multiple characters (for example,\n ``\'1<>2<>3\'.split(\'<>\')`` returns ``[\'1\', \'2\', \'3\']``). Splitting\n an empty string with a specified separator returns ``[\'\']``.\n\n If *sep* is not specified or is ``None``, a different splitting\n algorithm is applied: runs of consecutive whitespace are regarded\n as a single separator, and the result will contain no empty strings\n at the start or end if the string has leading or trailing\n whitespace. Consequently, splitting an empty string or a string\n consisting of just whitespace with a ``None`` separator returns\n ``[]``.\n\n For example, ``\' 1 2 3 \'.split()`` returns ``[\'1\', \'2\', \'3\']``,\n and ``\' 1 2 3 \'.split(None, 1)`` returns ``[\'1\', \'2 3 \']``.\n\nstr.splitlines([keepends])\n\n Return a list of the lines in the string, breaking at line\n boundaries. Line breaks are not included in the resulting list\n unless *keepends* is given and true.\n\nstr.startswith(prefix[, start[, end]])\n\n Return ``True`` if string starts with the *prefix*, otherwise\n return ``False``. *prefix* can also be a tuple of prefixes to look\n for. With optional *start*, test string beginning at that\n position. With optional *end*, stop comparing string at that\n position.\n\nstr.strip([chars])\n\n Return a copy of the string with the leading and trailing\n characters removed. The *chars* argument is a string specifying the\n set of characters to be removed. If omitted or ``None``, the\n *chars* argument defaults to removing whitespace. The *chars*\n argument is not a prefix or suffix; rather, all combinations of its\n values are stripped:\n\n >>> \' spacious \'.strip()\n \'spacious\'\n >>> \'www.example.com\'.strip(\'cmowz.\')\n \'example\'\n\nstr.swapcase()\n\n Return a copy of the string with uppercase characters converted to\n lowercase and vice versa.\n\nstr.title()\n\n Return a titlecased version of the string where words start with an\n uppercase character and the remaining characters are lowercase.\n\n The algorithm uses a simple language-independent definition of a\n word as groups of consecutive letters. The definition works in\n many contexts but it means that apostrophes in contractions and\n possessives form word boundaries, which may not be the desired\n result:\n\n >>> "they\'re bill\'s friends from the UK".title()\n "They\'Re Bill\'S Friends From The Uk"\n\n A workaround for apostrophes can be constructed using regular\n expressions:\n\n >>> import re\n >>> def titlecase(s):\n return re.sub(r"[A-Za-z]+(\'[A-Za-z]+)?",\n lambda mo: mo.group(0)[0].upper() +\n mo.group(0)[1:].lower(),\n s)\n\n >>> titlecase("they\'re bill\'s friends.")\n "They\'re Bill\'s Friends."\n\nstr.translate(map)\n\n Return a copy of the *s* where all characters have been mapped\n through the *map* which must be a dictionary of Unicode ordinals\n (integers) to Unicode ordinals, strings or ``None``. Unmapped\n characters are left untouched. Characters mapped to ``None`` are\n deleted.\n\n You can use ``str.maketrans()`` to create a translation map from\n character-to-character mappings in different formats.\n\n Note: An even more flexible approach is to create a custom character\n mapping codec using the ``codecs`` module (see\n ``encodings.cp1251`` for an example).\n\nstr.upper()\n\n Return a copy of the string converted to uppercase.\n\nstr.zfill(width)\n\n Return the numeric string left filled with zeros in a string of\n length *width*. A sign prefix is handled correctly. The original\n string is returned if *width* is less than ``len(s)``.\n\n\nOld String Formatting Operations\n================================\n\nNote: The formatting operations described here are obsolete and may go\n away in future versions of Python. Use the new *String Formatting*\n in new code.\n\nString objects have one unique built-in operation: the ``%`` operator\n(modulo). This is also known as the string *formatting* or\n*interpolation* operator. Given ``format % values`` (where *format* is\na string), ``%`` conversion specifications in *format* are replaced\nwith zero or more elements of *values*. The effect is similar to the\nusing ``sprintf()`` in the C language.\n\nIf *format* requires a single argument, *values* may be a single non-\ntuple object. [4] Otherwise, *values* must be a tuple with exactly\nthe number of items specified by the format string, or a single\nmapping object (for example, a dictionary).\n\nA conversion specifier contains two or more characters and has the\nfollowing components, which must occur in this order:\n\n1. The ``\'%\'`` character, which marks the start of the specifier.\n\n2. Mapping key (optional), consisting of a parenthesised sequence of\n characters (for example, ``(somename)``).\n\n3. Conversion flags (optional), which affect the result of some\n conversion types.\n\n4. Minimum field width (optional). If specified as an ``\'*\'``\n (asterisk), the actual width is read from the next element of the\n tuple in *values*, and the object to convert comes after the\n minimum field width and optional precision.\n\n5. Precision (optional), given as a ``\'.\'`` (dot) followed by the\n precision. If specified as ``\'*\'`` (an asterisk), the actual width\n is read from the next element of the tuple in *values*, and the\n value to convert comes after the precision.\n\n6. Length modifier (optional).\n\n7. Conversion type.\n\nWhen the right argument is a dictionary (or other mapping type), then\nthe formats in the string *must* include a parenthesised mapping key\ninto that dictionary inserted immediately after the ``\'%\'`` character.\nThe mapping key selects the value to be formatted from the mapping.\nFor example:\n\n>>> print(\'%(language)s has %(number)03d quote types.\' %\n... {\'language\': "Python", "number": 2})\nPython has 002 quote types.\n\nIn this case no ``*`` specifiers may occur in a format (since they\nrequire a sequential parameter list).\n\nThe conversion flag characters are:\n\n+-----------+-----------------------------------------------------------------------+\n| Flag | Meaning |\n+===========+=======================================================================+\n| ``\'#\'`` | The value conversion will use the "alternate form" (where defined |\n| | below). |\n+-----------+-----------------------------------------------------------------------+\n| ``\'0\'`` | The conversion will be zero padded for numeric values. |\n+-----------+-----------------------------------------------------------------------+\n| ``\'-\'`` | The converted value is left adjusted (overrides the ``\'0\'`` |\n| | conversion if both are given). |\n+-----------+-----------------------------------------------------------------------+\n| ``\' \'`` | (a space) A blank should be left before a positive number (or empty |\n| | string) produced by a signed conversion. |\n+-----------+-----------------------------------------------------------------------+\n| ``\'+\'`` | A sign character (``\'+\'`` or ``\'-\'``) will precede the conversion |\n| | (overrides a "space" flag). |\n+-----------+-----------------------------------------------------------------------+\n\nA length modifier (``h``, ``l``, or ``L``) may be present, but is\nignored as it is not necessary for Python -- so e.g. ``%ld`` is\nidentical to ``%d``.\n\nThe conversion types are:\n\n+--------------+-------------------------------------------------------+---------+\n| Conversion | Meaning | Notes |\n+==============+=======================================================+=========+\n| ``\'d\'`` | Signed integer decimal. | |\n+--------------+-------------------------------------------------------+---------+\n| ``\'i\'`` | Signed integer decimal. | |\n+--------------+-------------------------------------------------------+---------+\n| ``\'o\'`` | Signed octal value. | (1) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'u\'`` | Obsolete type -- it is identical to ``\'d\'``. | (7) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'x\'`` | Signed hexadecimal (lowercase). | (2) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'X\'`` | Signed hexadecimal (uppercase). | (2) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'e\'`` | Floating point exponential format (lowercase). | (3) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'E\'`` | Floating point exponential format (uppercase). | (3) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'f\'`` | Floating point decimal format. | (3) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'F\'`` | Floating point decimal format. | (3) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'g\'`` | Floating point format. Uses lowercase exponential | (4) |\n| | format if exponent is less than -4 or not less than | |\n| | precision, decimal format otherwise. | |\n+--------------+-------------------------------------------------------+---------+\n| ``\'G\'`` | Floating point format. Uses uppercase exponential | (4) |\n| | format if exponent is less than -4 or not less than | |\n| | precision, decimal format otherwise. | |\n+--------------+-------------------------------------------------------+---------+\n| ``\'c\'`` | Single character (accepts integer or single character | |\n| | string). | |\n+--------------+-------------------------------------------------------+---------+\n| ``\'r\'`` | String (converts any Python object using ``repr()``). | (5) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'s\'`` | String (converts any Python object using ``str()``). | |\n+--------------+-------------------------------------------------------+---------+\n| ``\'%\'`` | No argument is converted, results in a ``\'%\'`` | |\n| | character in the result. | |\n+--------------+-------------------------------------------------------+---------+\n\nNotes:\n\n1. The alternate form causes a leading zero (``\'0\'``) to be inserted\n between left-hand padding and the formatting of the number if the\n leading character of the result is not already a zero.\n\n2. The alternate form causes a leading ``\'0x\'`` or ``\'0X\'`` (depending\n on whether the ``\'x\'`` or ``\'X\'`` format was used) to be inserted\n between left-hand padding and the formatting of the number if the\n leading character of the result is not already a zero.\n\n3. The alternate form causes the result to always contain a decimal\n point, even if no digits follow it.\n\n The precision determines the number of digits after the decimal\n point and defaults to 6.\n\n4. The alternate form causes the result to always contain a decimal\n point, and trailing zeroes are not removed as they would otherwise\n be.\n\n The precision determines the number of significant digits before\n and after the decimal point and defaults to 6.\n\n5. The precision determines the maximal number of characters used.\n\n1. See **PEP 237**.\n\nSince Python strings have an explicit length, ``%s`` conversions do\nnot assume that ``\'\\0\'`` is the end of the string.\n\nChanged in version 3.1: ``%f`` conversions for numbers whose absolute\nvalue is over 1e50 are no longer replaced by ``%g`` conversions.\n\nAdditional string operations are defined in standard modules\n``string`` and ``re``.\n\n\nRange Type\n==========\n\nThe ``range`` type is an immutable sequence which is commonly used for\nlooping. The advantage of the ``range`` type is that an ``range``\nobject will always take the same amount of memory, no matter the size\nof the range it represents.\n\nRange objects have relatively little behavior: they support indexing,\ncontains, iteration, the ``len()`` function, and the following\nmethods:\n\nrange.count(x)\n\n Return the number of *i*\'s for which ``s[i] == x``.\n\n New in version 3.2.\n\nrange.index(x)\n\n Return the smallest *i* such that ``s[i] == x``. Raises\n ``ValueError`` when *x* is not in the range.\n\n New in version 3.2.\n\n\nMutable Sequence Types\n======================\n\nList and bytearray objects support additional operations that allow\nin-place modification of the object. Other mutable sequence types\n(when added to the language) should also support these operations.\nStrings and tuples are immutable sequence types: such objects cannot\nbe modified once created. The following operations are defined on\nmutable sequence types (where *x* is an arbitrary object).\n\nNote that while lists allow their items to be of any type, bytearray\nobject "items" are all integers in the range 0 <= x < 256.\n\n+--------------------------------+----------------------------------+-----------------------+\n| Operation | Result | Notes |\n+================================+==================================+=======================+\n| ``s[i] = x`` | item *i* of *s* is replaced by | |\n| | *x* | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s[i:j] = t`` | slice of *s* from *i* to *j* is | |\n| | replaced by the contents of the | |\n| | iterable *t* | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``del s[i:j]`` | same as ``s[i:j] = []`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s[i:j:k] = t`` | the elements of ``s[i:j:k]`` are | (1) |\n| | replaced by those of *t* | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``del s[i:j:k]`` | removes the elements of | |\n| | ``s[i:j:k]`` from the list | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.append(x)`` | same as ``s[len(s):len(s)] = | |\n| | [x]`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.extend(x)`` | same as ``s[len(s):len(s)] = x`` | (2) |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.count(x)`` | return number of *i*\'s for which | |\n| | ``s[i] == x`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.index(x[, i[, j]])`` | return smallest *k* such that | (3) |\n| | ``s[k] == x`` and ``i <= k < j`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.insert(i, x)`` | same as ``s[i:i] = [x]`` | (4) |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.pop([i])`` | same as ``x = s[i]; del s[i]; | (5) |\n| | return x`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.remove(x)`` | same as ``del s[s.index(x)]`` | (3) |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.reverse()`` | reverses the items of *s* in | (6) |\n| | place | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.sort([key[, reverse]])`` | sort the items of *s* in place | (6), (7), (8) |\n+--------------------------------+----------------------------------+-----------------------+\n\nNotes:\n\n1. *t* must have the same length as the slice it is replacing.\n\n2. *x* can be any iterable object.\n\n3. Raises ``ValueError`` when *x* is not found in *s*. When a negative\n index is passed as the second or third parameter to the ``index()``\n method, the sequence length is added, as for slice indices. If it\n is still negative, it is truncated to zero, as for slice indices.\n\n4. When a negative index is passed as the first parameter to the\n ``insert()`` method, the sequence length is added, as for slice\n indices. If it is still negative, it is truncated to zero, as for\n slice indices.\n\n5. The optional argument *i* defaults to ``-1``, so that by default\n the last item is removed and returned.\n\n6. The ``sort()`` and ``reverse()`` methods modify the sequence in\n place for economy of space when sorting or reversing a large\n sequence. To remind you that they operate by side effect, they\n don\'t return the sorted or reversed sequence.\n\n7. The ``sort()`` method takes optional arguments for controlling the\n comparisons. Each must be specified as a keyword argument.\n\n *key* specifies a function of one argument that is used to extract\n a comparison key from each list element: ``key=str.lower``. The\n default value is ``None``. Use ``functools.cmp_to_key()`` to\n convert an old-style *cmp* function to a *key* function.\n\n *reverse* is a boolean value. If set to ``True``, then the list\n elements are sorted as if each comparison were reversed.\n\n The ``sort()`` method is guaranteed to be stable. A sort is stable\n if it guarantees not to change the relative order of elements that\n compare equal --- this is helpful for sorting in multiple passes\n (for example, sort by department, then by salary grade).\n\n **CPython implementation detail:** While a list is being sorted,\n the effect of attempting to mutate, or even inspect, the list is\n undefined. The C implementation of Python makes the list appear\n empty for the duration, and raises ``ValueError`` if it can detect\n that the list has been mutated during a sort.\n\n8. ``sort()`` is not supported by ``bytearray`` objects.\n\n\nBytes and Byte Array Methods\n============================\n\nBytes and bytearray objects, being "strings of bytes", have all\nmethods found on strings, with the exception of ``encode()``,\n``format()`` and ``isidentifier()``, which do not make sense with\nthese types. For converting the objects to strings, they have a\n``decode()`` method.\n\nWherever one of these methods needs to interpret the bytes as\ncharacters (e.g. the ``is...()`` methods), the ASCII character set is\nassumed.\n\nNote: The methods on bytes and bytearray objects don\'t accept strings as\n their arguments, just as the methods on strings don\'t accept bytes\n as their arguments. For example, you have to write\n\n a = "abc"\n b = a.replace("a", "f")\n\n and\n\n a = b"abc"\n b = a.replace(b"a", b"f")\n\nbytes.decode(encoding="utf-8", errors="strict")\nbytearray.decode(encoding="utf-8", errors="strict")\n\n Return a string decoded from the given bytes. Default encoding is\n ``\'utf-8\'``. *errors* may be given to set a different error\n handling scheme. The default for *errors* is ``\'strict\'``, meaning\n that encoding errors raise a ``UnicodeError``. Other possible\n values are ``\'ignore\'``, ``\'replace\'`` and any other name\n registered via ``codecs.register_error()``, see section *Codec Base\n Classes*. For a list of possible encodings, see section *Standard\n Encodings*.\n\n Changed in version 3.1: Added support for keyword arguments.\n\nThe bytes and bytearray types have an additional class method:\n\nclassmethod bytes.fromhex(string)\nclassmethod bytearray.fromhex(string)\n\n This ``bytes`` class method returns a bytes or bytearray object,\n decoding the given string object. The string must contain two\n hexadecimal digits per byte, spaces are ignored.\n\n >>> bytes.fromhex(\'f0 f1f2 \')\n b\'\\xf0\\xf1\\xf2\'\n\nThe maketrans and translate methods differ in semantics from the\nversions available on strings:\n\nbytes.translate(table[, delete])\nbytearray.translate(table[, delete])\n\n Return a copy of the bytes or bytearray object where all bytes\n occurring in the optional argument *delete* are removed, and the\n remaining bytes have been mapped through the given translation\n table, which must be a bytes object of length 256.\n\n You can use the ``bytes.maketrans()`` method to create a\n translation table.\n\n Set the *table* argument to ``None`` for translations that only\n delete characters:\n\n >>> b\'read this short text\'.translate(None, b\'aeiou\')\n b\'rd ths shrt txt\'\n\nstatic bytes.maketrans(from, to)\nstatic bytearray.maketrans(from, to)\n\n This static method returns a translation table usable for\n ``bytes.translate()`` that will map each character in *from* into\n the character at the same position in *to*; *from* and *to* must be\n bytes objects and have the same length.\n\n New in version 3.1.\n', - 'typesseq-mutable': '\nMutable Sequence Types\n**********************\n\nList and bytearray objects support additional operations that allow\nin-place modification of the object. Other mutable sequence types\n(when added to the language) should also support these operations.\nStrings and tuples are immutable sequence types: such objects cannot\nbe modified once created. The following operations are defined on\nmutable sequence types (where *x* is an arbitrary object).\n\nNote that while lists allow their items to be of any type, bytearray\nobject "items" are all integers in the range 0 <= x < 256.\n\n+--------------------------------+----------------------------------+-----------------------+\n| Operation | Result | Notes |\n+================================+==================================+=======================+\n| ``s[i] = x`` | item *i* of *s* is replaced by | |\n| | *x* | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s[i:j] = t`` | slice of *s* from *i* to *j* is | |\n| | replaced by the contents of the | |\n| | iterable *t* | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``del s[i:j]`` | same as ``s[i:j] = []`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s[i:j:k] = t`` | the elements of ``s[i:j:k]`` are | (1) |\n| | replaced by those of *t* | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``del s[i:j:k]`` | removes the elements of | |\n| | ``s[i:j:k]`` from the list | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.append(x)`` | same as ``s[len(s):len(s)] = | |\n| | [x]`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.extend(x)`` | same as ``s[len(s):len(s)] = x`` | (2) |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.count(x)`` | return number of *i*\'s for which | |\n| | ``s[i] == x`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.index(x[, i[, j]])`` | return smallest *k* such that | (3) |\n| | ``s[k] == x`` and ``i <= k < j`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.insert(i, x)`` | same as ``s[i:i] = [x]`` | (4) |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.pop([i])`` | same as ``x = s[i]; del s[i]; | (5) |\n| | return x`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.remove(x)`` | same as ``del s[s.index(x)]`` | (3) |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.reverse()`` | reverses the items of *s* in | (6) |\n| | place | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.sort([key[, reverse]])`` | sort the items of *s* in place | (6), (7), (8) |\n+--------------------------------+----------------------------------+-----------------------+\n\nNotes:\n\n1. *t* must have the same length as the slice it is replacing.\n\n2. *x* can be any iterable object.\n\n3. Raises ``ValueError`` when *x* is not found in *s*. When a negative\n index is passed as the second or third parameter to the ``index()``\n method, the sequence length is added, as for slice indices. If it\n is still negative, it is truncated to zero, as for slice indices.\n\n4. When a negative index is passed as the first parameter to the\n ``insert()`` method, the sequence length is added, as for slice\n indices. If it is still negative, it is truncated to zero, as for\n slice indices.\n\n5. The optional argument *i* defaults to ``-1``, so that by default\n the last item is removed and returned.\n\n6. The ``sort()`` and ``reverse()`` methods modify the sequence in\n place for economy of space when sorting or reversing a large\n sequence. To remind you that they operate by side effect, they\n don\'t return the sorted or reversed sequence.\n\n7. The ``sort()`` method takes optional arguments for controlling the\n comparisons. Each must be specified as a keyword argument.\n\n *key* specifies a function of one argument that is used to extract\n a comparison key from each list element: ``key=str.lower``. The\n default value is ``None``. Use ``functools.cmp_to_key()`` to\n convert an old-style *cmp* function to a *key* function.\n\n *reverse* is a boolean value. If set to ``True``, then the list\n elements are sorted as if each comparison were reversed.\n\n The ``sort()`` method is guaranteed to be stable. A sort is stable\n if it guarantees not to change the relative order of elements that\n compare equal --- this is helpful for sorting in multiple passes\n (for example, sort by department, then by salary grade).\n\n **CPython implementation detail:** While a list is being sorted,\n the effect of attempting to mutate, or even inspect, the list is\n undefined. The C implementation of Python makes the list appear\n empty for the duration, and raises ``ValueError`` if it can detect\n that the list has been mutated during a sort.\n\n8. ``sort()`` is not supported by ``bytearray`` objects.\n', + 'typesseq': '\nSequence Types --- ``str``, ``bytes``, ``bytearray``, ``list``, ``tuple``, ``range``\n************************************************************************************\n\nThere are six sequence types: strings, byte sequences (``bytes``\nobjects), byte arrays (``bytearray`` objects), lists, tuples, and\nrange objects. For other containers see the built in ``dict`` and\n``set`` classes, and the ``collections`` module.\n\nStrings contain Unicode characters. Their literals are written in\nsingle or double quotes: ``\'xyzzy\'``, ``"frobozz"``. See *String and\nBytes literals* for more about string literals. In addition to the\nfunctionality described here, there are also string-specific methods\ndescribed in the *String Methods* section.\n\nBytes and bytearray objects contain single bytes -- the former is\nimmutable while the latter is a mutable sequence. Bytes objects can\nbe constructed the constructor, ``bytes()``, and from literals; use a\n``b`` prefix with normal string syntax: ``b\'xyzzy\'``. To construct\nbyte arrays, use the ``bytearray()`` function.\n\nWhile string objects are sequences of characters (represented by\nstrings of length 1), bytes and bytearray objects are sequences of\n*integers* (between 0 and 255), representing the ASCII value of single\nbytes. That means that for a bytes or bytearray object *b*, ``b[0]``\nwill be an integer, while ``b[0:1]`` will be a bytes or bytearray\nobject of length 1. The representation of bytes objects uses the\nliteral format (``b\'...\'``) since it is generally more useful than\ne.g. ``bytes([50, 19, 100])``. You can always convert a bytes object\ninto a list of integers using ``list(b)``.\n\nAlso, while in previous Python versions, byte strings and Unicode\nstrings could be exchanged for each other rather freely (barring\nencoding issues), strings and bytes are now completely separate\nconcepts. There\'s no implicit en-/decoding if you pass an object of\nthe wrong type. A string always compares unequal to a bytes or\nbytearray object.\n\nLists are constructed with square brackets, separating items with\ncommas: ``[a, b, c]``. Tuples are constructed by the comma operator\n(not within square brackets), with or without enclosing parentheses,\nbut an empty tuple must have the enclosing parentheses, such as ``a,\nb, c`` or ``()``. A single item tuple must have a trailing comma,\nsuch as ``(d,)``.\n\nObjects of type range are created using the ``range()`` function.\nThey don\'t support concatenation or repetition, and using ``min()`` or\n``max()`` on them is inefficient.\n\nMost sequence types support the following operations. The ``in`` and\n``not in`` operations have the same priorities as the comparison\noperations. The ``+`` and ``*`` operations have the same priority as\nthe corresponding numeric operations. [3] Additional methods are\nprovided for *Mutable Sequence Types*.\n\nThis table lists the sequence operations sorted in ascending priority\n(operations in the same box have the same priority). In the table,\n*s* and *t* are sequences of the same type; *n*, *i*, *j* and *k* are\nintegers.\n\n+--------------------+----------------------------------+------------+\n| Operation | Result | Notes |\n+====================+==================================+============+\n| ``x in s`` | ``True`` if an item of *s* is | (1) |\n| | equal to *x*, else ``False`` | |\n+--------------------+----------------------------------+------------+\n| ``x not in s`` | ``False`` if an item of *s* is | (1) |\n| | equal to *x*, else ``True`` | |\n+--------------------+----------------------------------+------------+\n| ``s + t`` | the concatenation of *s* and *t* | (6) |\n+--------------------+----------------------------------+------------+\n| ``s * n, n * s`` | *n* shallow copies of *s* | (2) |\n| | concatenated | |\n+--------------------+----------------------------------+------------+\n| ``s[i]`` | *i*\'th item of *s*, origin 0 | (3) |\n+--------------------+----------------------------------+------------+\n| ``s[i:j]`` | slice of *s* from *i* to *j* | (3)(4) |\n+--------------------+----------------------------------+------------+\n| ``s[i:j:k]`` | slice of *s* from *i* to *j* | (3)(5) |\n| | with step *k* | |\n+--------------------+----------------------------------+------------+\n| ``len(s)`` | length of *s* | |\n+--------------------+----------------------------------+------------+\n| ``min(s)`` | smallest item of *s* | |\n+--------------------+----------------------------------+------------+\n| ``max(s)`` | largest item of *s* | |\n+--------------------+----------------------------------+------------+\n| ``s.index(i)`` | index of the first occurence of | |\n| | *i* in *s* | |\n+--------------------+----------------------------------+------------+\n| ``s.count(i)`` | total number of occurences of | |\n| | *i* in *s* | |\n+--------------------+----------------------------------+------------+\n\nSequence types also support comparisons. In particular, tuples and\nlists are compared lexicographically by comparing corresponding\nelements. This means that to compare equal, every element must\ncompare equal and the two sequences must be of the same type and have\nthe same length. (For full details see *Comparisons* in the language\nreference.)\n\nNotes:\n\n1. When *s* is a string object, the ``in`` and ``not in`` operations\n act like a substring test.\n\n2. Values of *n* less than ``0`` are treated as ``0`` (which yields an\n empty sequence of the same type as *s*). Note also that the copies\n are shallow; nested structures are not copied. This often haunts\n new Python programmers; consider:\n\n >>> lists = [[]] * 3\n >>> lists\n [[], [], []]\n >>> lists[0].append(3)\n >>> lists\n [[3], [3], [3]]\n\n What has happened is that ``[[]]`` is a one-element list containing\n an empty list, so all three elements of ``[[]] * 3`` are (pointers\n to) this single empty list. Modifying any of the elements of\n ``lists`` modifies this single list. You can create a list of\n different lists this way:\n\n >>> lists = [[] for i in range(3)]\n >>> lists[0].append(3)\n >>> lists[1].append(5)\n >>> lists[2].append(7)\n >>> lists\n [[3], [5], [7]]\n\n3. If *i* or *j* is negative, the index is relative to the end of the\n string: ``len(s) + i`` or ``len(s) + j`` is substituted. But note\n that ``-0`` is still ``0``.\n\n4. The slice of *s* from *i* to *j* is defined as the sequence of\n items with index *k* such that ``i <= k < j``. If *i* or *j* is\n greater than ``len(s)``, use ``len(s)``. If *i* is omitted or\n ``None``, use ``0``. If *j* is omitted or ``None``, use\n ``len(s)``. If *i* is greater than or equal to *j*, the slice is\n empty.\n\n5. The slice of *s* from *i* to *j* with step *k* is defined as the\n sequence of items with index ``x = i + n*k`` such that ``0 <= n <\n (j-i)/k``. In other words, the indices are ``i``, ``i+k``,\n ``i+2*k``, ``i+3*k`` and so on, stopping when *j* is reached (but\n never including *j*). If *i* or *j* is greater than ``len(s)``,\n use ``len(s)``. If *i* or *j* are omitted or ``None``, they become\n "end" values (which end depends on the sign of *k*). Note, *k*\n cannot be zero. If *k* is ``None``, it is treated like ``1``.\n\n6. **CPython implementation detail:** If *s* and *t* are both strings,\n some Python implementations such as CPython can usually perform an\n in-place optimization for assignments of the form ``s = s + t`` or\n ``s += t``. When applicable, this optimization makes quadratic\n run-time much less likely. This optimization is both version and\n implementation dependent. For performance sensitive code, it is\n preferable to use the ``str.join()`` method which assures\n consistent linear concatenation performance across versions and\n implementations.\n\n\nString Methods\n==============\n\nString objects support the methods listed below.\n\nIn addition, Python\'s strings support the sequence type methods\ndescribed in the *Sequence Types --- str, bytes, bytearray, list,\ntuple, range* section. To output formatted strings, see the *String\nFormatting* section. Also, see the ``re`` module for string functions\nbased on regular expressions.\n\nstr.capitalize()\n\n Return a copy of the string with its first character capitalized\n and the rest lowercased.\n\nstr.center(width[, fillchar])\n\n Return centered in a string of length *width*. Padding is done\n using the specified *fillchar* (default is a space).\n\nstr.count(sub[, start[, end]])\n\n Return the number of non-overlapping occurrences of substring *sub*\n in the range [*start*, *end*]. Optional arguments *start* and\n *end* are interpreted as in slice notation.\n\nstr.encode(encoding="utf-8", errors="strict")\n\n Return an encoded version of the string as a bytes object. Default\n encoding is ``\'utf-8\'``. *errors* may be given to set a different\n error handling scheme. The default for *errors* is ``\'strict\'``,\n meaning that encoding errors raise a ``UnicodeError``. Other\n possible values are ``\'ignore\'``, ``\'replace\'``,\n ``\'xmlcharrefreplace\'``, ``\'backslashreplace\'`` and any other name\n registered via ``codecs.register_error()``, see section *Codec Base\n Classes*. For a list of possible encodings, see section *Standard\n Encodings*.\n\n Changed in version 3.1: Support for keyword arguments added.\n\nstr.endswith(suffix[, start[, end]])\n\n Return ``True`` if the string ends with the specified *suffix*,\n otherwise return ``False``. *suffix* can also be a tuple of\n suffixes to look for. With optional *start*, test beginning at\n that position. With optional *end*, stop comparing at that\n position.\n\nstr.expandtabs([tabsize])\n\n Return a copy of the string where all tab characters are replaced\n by one or more spaces, depending on the current column and the\n given tab size. The column number is reset to zero after each\n newline occurring in the string. If *tabsize* is not given, a tab\n size of ``8`` characters is assumed. This doesn\'t understand other\n non-printing characters or escape sequences.\n\nstr.find(sub[, start[, end]])\n\n Return the lowest index in the string where substring *sub* is\n found, such that *sub* is contained in the slice ``s[start:end]``.\n Optional arguments *start* and *end* are interpreted as in slice\n notation. Return ``-1`` if *sub* is not found.\n\nstr.format(*args, **kwargs)\n\n Perform a string formatting operation. The string on which this\n method is called can contain literal text or replacement fields\n delimited by braces ``{}``. Each replacement field contains either\n the numeric index of a positional argument, or the name of a\n keyword argument. Returns a copy of the string where each\n replacement field is replaced with the string value of the\n corresponding argument.\n\n >>> "The sum of 1 + 2 is {0}".format(1+2)\n \'The sum of 1 + 2 is 3\'\n\n See *Format String Syntax* for a description of the various\n formatting options that can be specified in format strings.\n\nstr.format_map(mapping)\n\n Similar to ``str.format(**mapping)``, except that ``mapping`` is\n used directly and not copied to a ``dict`` . This is useful if for\n example ``mapping`` is a dict subclass:\n\n >>> class Default(dict):\n ... def __missing__(self, key):\n ... return key\n ...\n >>> \'{name} was born in {country}\'.format_map(Default(name=\'Guido\'))\n \'Guido was born in country\'\n\n New in version 3.2.\n\nstr.index(sub[, start[, end]])\n\n Like ``find()``, but raise ``ValueError`` when the substring is not\n found.\n\nstr.isalnum()\n\n Return true if all characters in the string are alphanumeric and\n there is at least one character, false otherwise. A character\n ``c`` is alphanumeric if one of the following returns ``True``:\n ``c.isalpha()``, ``c.isdecimal()``, ``c.isdigit()``, or\n ``c.isnumeric()``.\n\nstr.isalpha()\n\n Return true if all characters in the string are alphabetic and\n there is at least one character, false otherwise. Alphabetic\n characters are those characters defined in the Unicode character\n database as "Letter", i.e., those with general category property\n being one of "Lm", "Lt", "Lu", "Ll", or "Lo". Note that this is\n different from the "Alphabetic" property defined in the Unicode\n Standard.\n\nstr.isdecimal()\n\n Return true if all characters in the string are decimal characters\n and there is at least one character, false otherwise. Decimal\n characters are those from general category "Nd". This category\n includes digit characters, and all characters that that can be used\n to form decimal-radix numbers, e.g. U+0660, ARABIC-INDIC DIGIT\n ZERO.\n\nstr.isdigit()\n\n Return true if all characters in the string are digits and there is\n at least one character, false otherwise. Digits include decimal\n characters and digits that need special handling, such as the\n compatibility superscript digits. Formally, a digit is a character\n that has the property value Numeric_Type=Digit or\n Numeric_Type=Decimal.\n\nstr.isidentifier()\n\n Return true if the string is a valid identifier according to the\n language definition, section *Identifiers and keywords*.\n\nstr.islower()\n\n Return true if all cased characters in the string are lowercase and\n there is at least one cased character, false otherwise. Cased\n characters are those with general category property being one of\n "Lu", "Ll", or "Lt" and lowercase characters are those with general\n category property "Ll".\n\nstr.isnumeric()\n\n Return true if all characters in the string are numeric characters,\n and there is at least one character, false otherwise. Numeric\n characters include digit characters, and all characters that have\n the Unicode numeric value property, e.g. U+2155, VULGAR FRACTION\n ONE FIFTH. Formally, numeric characters are those with the\n property value Numeric_Type=Digit, Numeric_Type=Decimal or\n Numeric_Type=Numeric.\n\nstr.isprintable()\n\n Return true if all characters in the string are printable or the\n string is empty, false otherwise. Nonprintable characters are\n those characters defined in the Unicode character database as\n "Other" or "Separator", excepting the ASCII space (0x20) which is\n considered printable. (Note that printable characters in this\n context are those which should not be escaped when ``repr()`` is\n invoked on a string. It has no bearing on the handling of strings\n written to ``sys.stdout`` or ``sys.stderr``.)\n\nstr.isspace()\n\n Return true if there are only whitespace characters in the string\n and there is at least one character, false otherwise. Whitespace\n characters are those characters defined in the Unicode character\n database as "Other" or "Separator" and those with bidirectional\n property being one of "WS", "B", or "S".\n\nstr.istitle()\n\n Return true if the string is a titlecased string and there is at\n least one character, for example uppercase characters may only\n follow uncased characters and lowercase characters only cased ones.\n Return false otherwise.\n\nstr.isupper()\n\n Return true if all cased characters in the string are uppercase and\n there is at least one cased character, false otherwise. Cased\n characters are those with general category property being one of\n "Lu", "Ll", or "Lt" and uppercase characters are those with general\n category property "Lu".\n\nstr.join(iterable)\n\n Return a string which is the concatenation of the strings in the\n *iterable* *iterable*. A ``TypeError`` will be raised if there are\n any non-string values in *seq*, including ``bytes`` objects. The\n separator between elements is the string providing this method.\n\nstr.ljust(width[, fillchar])\n\n Return the string left justified in a string of length *width*.\n Padding is done using the specified *fillchar* (default is a\n space). The original string is returned if *width* is less than\n ``len(s)``.\n\nstr.lower()\n\n Return a copy of the string converted to lowercase.\n\nstr.lstrip([chars])\n\n Return a copy of the string with leading characters removed. The\n *chars* argument is a string specifying the set of characters to be\n removed. If omitted or ``None``, the *chars* argument defaults to\n removing whitespace. The *chars* argument is not a prefix; rather,\n all combinations of its values are stripped:\n\n >>> \' spacious \'.lstrip()\n \'spacious \'\n >>> \'www.example.com\'.lstrip(\'cmowz.\')\n \'example.com\'\n\nstatic str.maketrans(x[, y[, z]])\n\n This static method returns a translation table usable for\n ``str.translate()``.\n\n If there is only one argument, it must be a dictionary mapping\n Unicode ordinals (integers) or characters (strings of length 1) to\n Unicode ordinals, strings (of arbitrary lengths) or None.\n Character keys will then be converted to ordinals.\n\n If there are two arguments, they must be strings of equal length,\n and in the resulting dictionary, each character in x will be mapped\n to the character at the same position in y. If there is a third\n argument, it must be a string, whose characters will be mapped to\n None in the result.\n\nstr.partition(sep)\n\n Split the string at the first occurrence of *sep*, and return a\n 3-tuple containing the part before the separator, the separator\n itself, and the part after the separator. If the separator is not\n found, return a 3-tuple containing the string itself, followed by\n two empty strings.\n\nstr.replace(old, new[, count])\n\n Return a copy of the string with all occurrences of substring *old*\n replaced by *new*. If the optional argument *count* is given, only\n the first *count* occurrences are replaced.\n\nstr.rfind(sub[, start[, end]])\n\n Return the highest index in the string where substring *sub* is\n found, such that *sub* is contained within ``s[start:end]``.\n Optional arguments *start* and *end* are interpreted as in slice\n notation. Return ``-1`` on failure.\n\nstr.rindex(sub[, start[, end]])\n\n Like ``rfind()`` but raises ``ValueError`` when the substring *sub*\n is not found.\n\nstr.rjust(width[, fillchar])\n\n Return the string right justified in a string of length *width*.\n Padding is done using the specified *fillchar* (default is a\n space). The original string is returned if *width* is less than\n ``len(s)``.\n\nstr.rpartition(sep)\n\n Split the string at the last occurrence of *sep*, and return a\n 3-tuple containing the part before the separator, the separator\n itself, and the part after the separator. If the separator is not\n found, return a 3-tuple containing two empty strings, followed by\n the string itself.\n\nstr.rsplit([sep[, maxsplit]])\n\n Return a list of the words in the string, using *sep* as the\n delimiter string. If *maxsplit* is given, at most *maxsplit* splits\n are done, the *rightmost* ones. If *sep* is not specified or\n ``None``, any whitespace string is a separator. Except for\n splitting from the right, ``rsplit()`` behaves like ``split()``\n which is described in detail below.\n\nstr.rstrip([chars])\n\n Return a copy of the string with trailing characters removed. The\n *chars* argument is a string specifying the set of characters to be\n removed. If omitted or ``None``, the *chars* argument defaults to\n removing whitespace. The *chars* argument is not a suffix; rather,\n all combinations of its values are stripped:\n\n >>> \' spacious \'.rstrip()\n \' spacious\'\n >>> \'mississippi\'.rstrip(\'ipz\')\n \'mississ\'\n\nstr.split([sep[, maxsplit]])\n\n Return a list of the words in the string, using *sep* as the\n delimiter string. If *maxsplit* is given, at most *maxsplit*\n splits are done (thus, the list will have at most ``maxsplit+1``\n elements). If *maxsplit* is not specified, then there is no limit\n on the number of splits (all possible splits are made).\n\n If *sep* is given, consecutive delimiters are not grouped together\n and are deemed to delimit empty strings (for example,\n ``\'1,,2\'.split(\',\')`` returns ``[\'1\', \'\', \'2\']``). The *sep*\n argument may consist of multiple characters (for example,\n ``\'1<>2<>3\'.split(\'<>\')`` returns ``[\'1\', \'2\', \'3\']``). Splitting\n an empty string with a specified separator returns ``[\'\']``.\n\n If *sep* is not specified or is ``None``, a different splitting\n algorithm is applied: runs of consecutive whitespace are regarded\n as a single separator, and the result will contain no empty strings\n at the start or end if the string has leading or trailing\n whitespace. Consequently, splitting an empty string or a string\n consisting of just whitespace with a ``None`` separator returns\n ``[]``.\n\n For example, ``\' 1 2 3 \'.split()`` returns ``[\'1\', \'2\', \'3\']``,\n and ``\' 1 2 3 \'.split(None, 1)`` returns ``[\'1\', \'2 3 \']``.\n\nstr.splitlines([keepends])\n\n Return a list of the lines in the string, breaking at line\n boundaries. Line breaks are not included in the resulting list\n unless *keepends* is given and true.\n\nstr.startswith(prefix[, start[, end]])\n\n Return ``True`` if string starts with the *prefix*, otherwise\n return ``False``. *prefix* can also be a tuple of prefixes to look\n for. With optional *start*, test string beginning at that\n position. With optional *end*, stop comparing string at that\n position.\n\nstr.strip([chars])\n\n Return a copy of the string with the leading and trailing\n characters removed. The *chars* argument is a string specifying the\n set of characters to be removed. If omitted or ``None``, the\n *chars* argument defaults to removing whitespace. The *chars*\n argument is not a prefix or suffix; rather, all combinations of its\n values are stripped:\n\n >>> \' spacious \'.strip()\n \'spacious\'\n >>> \'www.example.com\'.strip(\'cmowz.\')\n \'example\'\n\nstr.swapcase()\n\n Return a copy of the string with uppercase characters converted to\n lowercase and vice versa.\n\nstr.title()\n\n Return a titlecased version of the string where words start with an\n uppercase character and the remaining characters are lowercase.\n\n The algorithm uses a simple language-independent definition of a\n word as groups of consecutive letters. The definition works in\n many contexts but it means that apostrophes in contractions and\n possessives form word boundaries, which may not be the desired\n result:\n\n >>> "they\'re bill\'s friends from the UK".title()\n "They\'Re Bill\'S Friends From The Uk"\n\n A workaround for apostrophes can be constructed using regular\n expressions:\n\n >>> import re\n >>> def titlecase(s):\n return re.sub(r"[A-Za-z]+(\'[A-Za-z]+)?",\n lambda mo: mo.group(0)[0].upper() +\n mo.group(0)[1:].lower(),\n s)\n\n >>> titlecase("they\'re bill\'s friends.")\n "They\'re Bill\'s Friends."\n\nstr.translate(map)\n\n Return a copy of the *s* where all characters have been mapped\n through the *map* which must be a dictionary of Unicode ordinals\n (integers) to Unicode ordinals, strings or ``None``. Unmapped\n characters are left untouched. Characters mapped to ``None`` are\n deleted.\n\n You can use ``str.maketrans()`` to create a translation map from\n character-to-character mappings in different formats.\n\n Note: An even more flexible approach is to create a custom character\n mapping codec using the ``codecs`` module (see\n ``encodings.cp1251`` for an example).\n\nstr.upper()\n\n Return a copy of the string converted to uppercase.\n\nstr.zfill(width)\n\n Return the numeric string left filled with zeros in a string of\n length *width*. A sign prefix is handled correctly. The original\n string is returned if *width* is less than ``len(s)``.\n\n\nOld String Formatting Operations\n================================\n\nNote: The formatting operations described here are obsolete and may go\n away in future versions of Python. Use the new *String Formatting*\n in new code.\n\nString objects have one unique built-in operation: the ``%`` operator\n(modulo). This is also known as the string *formatting* or\n*interpolation* operator. Given ``format % values`` (where *format* is\na string), ``%`` conversion specifications in *format* are replaced\nwith zero or more elements of *values*. The effect is similar to the\nusing ``sprintf()`` in the C language.\n\nIf *format* requires a single argument, *values* may be a single non-\ntuple object. [4] Otherwise, *values* must be a tuple with exactly\nthe number of items specified by the format string, or a single\nmapping object (for example, a dictionary).\n\nA conversion specifier contains two or more characters and has the\nfollowing components, which must occur in this order:\n\n1. The ``\'%\'`` character, which marks the start of the specifier.\n\n2. Mapping key (optional), consisting of a parenthesised sequence of\n characters (for example, ``(somename)``).\n\n3. Conversion flags (optional), which affect the result of some\n conversion types.\n\n4. Minimum field width (optional). If specified as an ``\'*\'``\n (asterisk), the actual width is read from the next element of the\n tuple in *values*, and the object to convert comes after the\n minimum field width and optional precision.\n\n5. Precision (optional), given as a ``\'.\'`` (dot) followed by the\n precision. If specified as ``\'*\'`` (an asterisk), the actual width\n is read from the next element of the tuple in *values*, and the\n value to convert comes after the precision.\n\n6. Length modifier (optional).\n\n7. Conversion type.\n\nWhen the right argument is a dictionary (or other mapping type), then\nthe formats in the string *must* include a parenthesised mapping key\ninto that dictionary inserted immediately after the ``\'%\'`` character.\nThe mapping key selects the value to be formatted from the mapping.\nFor example:\n\n>>> print(\'%(language)s has %(number)03d quote types.\' %\n... {\'language\': "Python", "number": 2})\nPython has 002 quote types.\n\nIn this case no ``*`` specifiers may occur in a format (since they\nrequire a sequential parameter list).\n\nThe conversion flag characters are:\n\n+-----------+-----------------------------------------------------------------------+\n| Flag | Meaning |\n+===========+=======================================================================+\n| ``\'#\'`` | The value conversion will use the "alternate form" (where defined |\n| | below). |\n+-----------+-----------------------------------------------------------------------+\n| ``\'0\'`` | The conversion will be zero padded for numeric values. |\n+-----------+-----------------------------------------------------------------------+\n| ``\'-\'`` | The converted value is left adjusted (overrides the ``\'0\'`` |\n| | conversion if both are given). |\n+-----------+-----------------------------------------------------------------------+\n| ``\' \'`` | (a space) A blank should be left before a positive number (or empty |\n| | string) produced by a signed conversion. |\n+-----------+-----------------------------------------------------------------------+\n| ``\'+\'`` | A sign character (``\'+\'`` or ``\'-\'``) will precede the conversion |\n| | (overrides a "space" flag). |\n+-----------+-----------------------------------------------------------------------+\n\nA length modifier (``h``, ``l``, or ``L``) may be present, but is\nignored as it is not necessary for Python -- so e.g. ``%ld`` is\nidentical to ``%d``.\n\nThe conversion types are:\n\n+--------------+-------------------------------------------------------+---------+\n| Conversion | Meaning | Notes |\n+==============+=======================================================+=========+\n| ``\'d\'`` | Signed integer decimal. | |\n+--------------+-------------------------------------------------------+---------+\n| ``\'i\'`` | Signed integer decimal. | |\n+--------------+-------------------------------------------------------+---------+\n| ``\'o\'`` | Signed octal value. | (1) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'u\'`` | Obsolete type -- it is identical to ``\'d\'``. | (7) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'x\'`` | Signed hexadecimal (lowercase). | (2) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'X\'`` | Signed hexadecimal (uppercase). | (2) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'e\'`` | Floating point exponential format (lowercase). | (3) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'E\'`` | Floating point exponential format (uppercase). | (3) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'f\'`` | Floating point decimal format. | (3) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'F\'`` | Floating point decimal format. | (3) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'g\'`` | Floating point format. Uses lowercase exponential | (4) |\n| | format if exponent is less than -4 or not less than | |\n| | precision, decimal format otherwise. | |\n+--------------+-------------------------------------------------------+---------+\n| ``\'G\'`` | Floating point format. Uses uppercase exponential | (4) |\n| | format if exponent is less than -4 or not less than | |\n| | precision, decimal format otherwise. | |\n+--------------+-------------------------------------------------------+---------+\n| ``\'c\'`` | Single character (accepts integer or single character | |\n| | string). | |\n+--------------+-------------------------------------------------------+---------+\n| ``\'r\'`` | String (converts any Python object using ``repr()``). | (5) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'s\'`` | String (converts any Python object using ``str()``). | |\n+--------------+-------------------------------------------------------+---------+\n| ``\'%\'`` | No argument is converted, results in a ``\'%\'`` | |\n| | character in the result. | |\n+--------------+-------------------------------------------------------+---------+\n\nNotes:\n\n1. The alternate form causes a leading zero (``\'0\'``) to be inserted\n between left-hand padding and the formatting of the number if the\n leading character of the result is not already a zero.\n\n2. The alternate form causes a leading ``\'0x\'`` or ``\'0X\'`` (depending\n on whether the ``\'x\'`` or ``\'X\'`` format was used) to be inserted\n between left-hand padding and the formatting of the number if the\n leading character of the result is not already a zero.\n\n3. The alternate form causes the result to always contain a decimal\n point, even if no digits follow it.\n\n The precision determines the number of digits after the decimal\n point and defaults to 6.\n\n4. The alternate form causes the result to always contain a decimal\n point, and trailing zeroes are not removed as they would otherwise\n be.\n\n The precision determines the number of significant digits before\n and after the decimal point and defaults to 6.\n\n5. The precision determines the maximal number of characters used.\n\n1. See **PEP 237**.\n\nSince Python strings have an explicit length, ``%s`` conversions do\nnot assume that ``\'\\0\'`` is the end of the string.\n\nChanged in version 3.1: ``%f`` conversions for numbers whose absolute\nvalue is over 1e50 are no longer replaced by ``%g`` conversions.\n\nAdditional string operations are defined in standard modules\n``string`` and ``re``.\n\n\nRange Type\n==========\n\nThe ``range`` type is an immutable sequence which is commonly used for\nlooping. The advantage of the ``range`` type is that an ``range``\nobject will always take the same amount of memory, no matter the size\nof the range it represents.\n\nRange objects have relatively little behavior: they support indexing,\ncontains, iteration, the ``len()`` function, and the following\nmethods:\n\nrange.count(x)\n\n Return the number of *i*\'s for which ``s[i] == x``.\n\n New in version 3.2.\n\nrange.index(x)\n\n Return the smallest *i* such that ``s[i] == x``. Raises\n ``ValueError`` when *x* is not in the range.\n\n New in version 3.2.\n\n\nMutable Sequence Types\n======================\n\nList and bytearray objects support additional operations that allow\nin-place modification of the object. Other mutable sequence types\n(when added to the language) should also support these operations.\nStrings and tuples are immutable sequence types: such objects cannot\nbe modified once created. The following operations are defined on\nmutable sequence types (where *x* is an arbitrary object).\n\nNote that while lists allow their items to be of any type, bytearray\nobject "items" are all integers in the range 0 <= x < 256.\n\n+--------------------------------+----------------------------------+-----------------------+\n| Operation | Result | Notes |\n+================================+==================================+=======================+\n| ``s[i] = x`` | item *i* of *s* is replaced by | |\n| | *x* | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s[i:j] = t`` | slice of *s* from *i* to *j* is | |\n| | replaced by the contents of the | |\n| | iterable *t* | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``del s[i:j]`` | same as ``s[i:j] = []`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s[i:j:k] = t`` | the elements of ``s[i:j:k]`` are | (1) |\n| | replaced by those of *t* | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``del s[i:j:k]`` | removes the elements of | |\n| | ``s[i:j:k]`` from the list | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.append(x)`` | same as ``s[len(s):len(s)] = | |\n| | [x]`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.extend(x)`` | same as ``s[len(s):len(s)] = x`` | (2) |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.clear()`` | remove all items from ``s`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.copy()`` | return a shallow copy of ``s`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.count(x)`` | return number of *i*\'s for which | |\n| | ``s[i] == x`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.index(x[, i[, j]])`` | return smallest *k* such that | (3) |\n| | ``s[k] == x`` and ``i <= k < j`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.insert(i, x)`` | same as ``s[i:i] = [x]`` | (4) |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.pop([i])`` | same as ``x = s[i]; del s[i]; | (5) |\n| | return x`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.remove(x)`` | same as ``del s[s.index(x)]`` | (3) |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.reverse()`` | reverses the items of *s* in | (6) |\n| | place | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.sort([key[, reverse]])`` | sort the items of *s* in place | (6), (7), (8) |\n+--------------------------------+----------------------------------+-----------------------+\n\nNotes:\n\n1. *t* must have the same length as the slice it is replacing.\n\n2. *x* can be any iterable object.\n\n3. Raises ``ValueError`` when *x* is not found in *s*. When a negative\n index is passed as the second or third parameter to the ``index()``\n method, the sequence length is added, as for slice indices. If it\n is still negative, it is truncated to zero, as for slice indices.\n\n4. When a negative index is passed as the first parameter to the\n ``insert()`` method, the sequence length is added, as for slice\n indices. If it is still negative, it is truncated to zero, as for\n slice indices.\n\n5. The optional argument *i* defaults to ``-1``, so that by default\n the last item is removed and returned.\n\n6. The ``sort()`` and ``reverse()`` methods modify the sequence in\n place for economy of space when sorting or reversing a large\n sequence. To remind you that they operate by side effect, they\n don\'t return the sorted or reversed sequence.\n\n7. The ``sort()`` method takes optional arguments for controlling the\n comparisons. Each must be specified as a keyword argument.\n\n *key* specifies a function of one argument that is used to extract\n a comparison key from each list element: ``key=str.lower``. The\n default value is ``None``. Use ``functools.cmp_to_key()`` to\n convert an old-style *cmp* function to a *key* function.\n\n *reverse* is a boolean value. If set to ``True``, then the list\n elements are sorted as if each comparison were reversed.\n\n The ``sort()`` method is guaranteed to be stable. A sort is stable\n if it guarantees not to change the relative order of elements that\n compare equal --- this is helpful for sorting in multiple passes\n (for example, sort by department, then by salary grade).\n\n **CPython implementation detail:** While a list is being sorted,\n the effect of attempting to mutate, or even inspect, the list is\n undefined. The C implementation of Python makes the list appear\n empty for the duration, and raises ``ValueError`` if it can detect\n that the list has been mutated during a sort.\n\n8. ``sort()`` is not supported by ``bytearray`` objects.\n\n New in version 3.3: ``clear()`` and ``copy()`` methods.\n\n\nBytes and Byte Array Methods\n============================\n\nBytes and bytearray objects, being "strings of bytes", have all\nmethods found on strings, with the exception of ``encode()``,\n``format()`` and ``isidentifier()``, which do not make sense with\nthese types. For converting the objects to strings, they have a\n``decode()`` method.\n\nWherever one of these methods needs to interpret the bytes as\ncharacters (e.g. the ``is...()`` methods), the ASCII character set is\nassumed.\n\nNote: The methods on bytes and bytearray objects don\'t accept strings as\n their arguments, just as the methods on strings don\'t accept bytes\n as their arguments. For example, you have to write\n\n a = "abc"\n b = a.replace("a", "f")\n\n and\n\n a = b"abc"\n b = a.replace(b"a", b"f")\n\nbytes.decode(encoding="utf-8", errors="strict")\nbytearray.decode(encoding="utf-8", errors="strict")\n\n Return a string decoded from the given bytes. Default encoding is\n ``\'utf-8\'``. *errors* may be given to set a different error\n handling scheme. The default for *errors* is ``\'strict\'``, meaning\n that encoding errors raise a ``UnicodeError``. Other possible\n values are ``\'ignore\'``, ``\'replace\'`` and any other name\n registered via ``codecs.register_error()``, see section *Codec Base\n Classes*. For a list of possible encodings, see section *Standard\n Encodings*.\n\n Changed in version 3.1: Added support for keyword arguments.\n\nThe bytes and bytearray types have an additional class method:\n\nclassmethod bytes.fromhex(string)\nclassmethod bytearray.fromhex(string)\n\n This ``bytes`` class method returns a bytes or bytearray object,\n decoding the given string object. The string must contain two\n hexadecimal digits per byte, spaces are ignored.\n\n >>> bytes.fromhex(\'f0 f1f2 \')\n b\'\\xf0\\xf1\\xf2\'\n\nThe maketrans and translate methods differ in semantics from the\nversions available on strings:\n\nbytes.translate(table[, delete])\nbytearray.translate(table[, delete])\n\n Return a copy of the bytes or bytearray object where all bytes\n occurring in the optional argument *delete* are removed, and the\n remaining bytes have been mapped through the given translation\n table, which must be a bytes object of length 256.\n\n You can use the ``bytes.maketrans()`` method to create a\n translation table.\n\n Set the *table* argument to ``None`` for translations that only\n delete characters:\n\n >>> b\'read this short text\'.translate(None, b\'aeiou\')\n b\'rd ths shrt txt\'\n\nstatic bytes.maketrans(from, to)\nstatic bytearray.maketrans(from, to)\n\n This static method returns a translation table usable for\n ``bytes.translate()`` that will map each character in *from* into\n the character at the same position in *to*; *from* and *to* must be\n bytes objects and have the same length.\n\n New in version 3.1.\n', + 'typesseq-mutable': '\nMutable Sequence Types\n**********************\n\nList and bytearray objects support additional operations that allow\nin-place modification of the object. Other mutable sequence types\n(when added to the language) should also support these operations.\nStrings and tuples are immutable sequence types: such objects cannot\nbe modified once created. The following operations are defined on\nmutable sequence types (where *x* is an arbitrary object).\n\nNote that while lists allow their items to be of any type, bytearray\nobject "items" are all integers in the range 0 <= x < 256.\n\n+--------------------------------+----------------------------------+-----------------------+\n| Operation | Result | Notes |\n+================================+==================================+=======================+\n| ``s[i] = x`` | item *i* of *s* is replaced by | |\n| | *x* | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s[i:j] = t`` | slice of *s* from *i* to *j* is | |\n| | replaced by the contents of the | |\n| | iterable *t* | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``del s[i:j]`` | same as ``s[i:j] = []`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s[i:j:k] = t`` | the elements of ``s[i:j:k]`` are | (1) |\n| | replaced by those of *t* | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``del s[i:j:k]`` | removes the elements of | |\n| | ``s[i:j:k]`` from the list | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.append(x)`` | same as ``s[len(s):len(s)] = | |\n| | [x]`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.extend(x)`` | same as ``s[len(s):len(s)] = x`` | (2) |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.clear()`` | remove all items from ``s`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.copy()`` | return a shallow copy of ``s`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.count(x)`` | return number of *i*\'s for which | |\n| | ``s[i] == x`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.index(x[, i[, j]])`` | return smallest *k* such that | (3) |\n| | ``s[k] == x`` and ``i <= k < j`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.insert(i, x)`` | same as ``s[i:i] = [x]`` | (4) |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.pop([i])`` | same as ``x = s[i]; del s[i]; | (5) |\n| | return x`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.remove(x)`` | same as ``del s[s.index(x)]`` | (3) |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.reverse()`` | reverses the items of *s* in | (6) |\n| | place | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.sort([key[, reverse]])`` | sort the items of *s* in place | (6), (7), (8) |\n+--------------------------------+----------------------------------+-----------------------+\n\nNotes:\n\n1. *t* must have the same length as the slice it is replacing.\n\n2. *x* can be any iterable object.\n\n3. Raises ``ValueError`` when *x* is not found in *s*. When a negative\n index is passed as the second or third parameter to the ``index()``\n method, the sequence length is added, as for slice indices. If it\n is still negative, it is truncated to zero, as for slice indices.\n\n4. When a negative index is passed as the first parameter to the\n ``insert()`` method, the sequence length is added, as for slice\n indices. If it is still negative, it is truncated to zero, as for\n slice indices.\n\n5. The optional argument *i* defaults to ``-1``, so that by default\n the last item is removed and returned.\n\n6. The ``sort()`` and ``reverse()`` methods modify the sequence in\n place for economy of space when sorting or reversing a large\n sequence. To remind you that they operate by side effect, they\n don\'t return the sorted or reversed sequence.\n\n7. The ``sort()`` method takes optional arguments for controlling the\n comparisons. Each must be specified as a keyword argument.\n\n *key* specifies a function of one argument that is used to extract\n a comparison key from each list element: ``key=str.lower``. The\n default value is ``None``. Use ``functools.cmp_to_key()`` to\n convert an old-style *cmp* function to a *key* function.\n\n *reverse* is a boolean value. If set to ``True``, then the list\n elements are sorted as if each comparison were reversed.\n\n The ``sort()`` method is guaranteed to be stable. A sort is stable\n if it guarantees not to change the relative order of elements that\n compare equal --- this is helpful for sorting in multiple passes\n (for example, sort by department, then by salary grade).\n\n **CPython implementation detail:** While a list is being sorted,\n the effect of attempting to mutate, or even inspect, the list is\n undefined. The C implementation of Python makes the list appear\n empty for the duration, and raises ``ValueError`` if it can detect\n that the list has been mutated during a sort.\n\n8. ``sort()`` is not supported by ``bytearray`` objects.\n\n New in version 3.3: ``clear()`` and ``copy()`` methods.\n', 'unary': '\nUnary arithmetic and bitwise operations\n***************************************\n\nAll unary arithmetic and bitwise operations have the same priority:\n\n u_expr ::= power | "-" u_expr | "+" u_expr | "~" u_expr\n\nThe unary ``-`` (minus) operator yields the negation of its numeric\nargument.\n\nThe unary ``+`` (plus) operator yields its numeric argument unchanged.\n\nThe unary ``~`` (invert) operator yields the bitwise inversion of its\ninteger argument. The bitwise inversion of ``x`` is defined as\n``-(x+1)``. It only applies to integral numbers.\n\nIn all three cases, if the argument does not have the proper type, a\n``TypeError`` exception is raised.\n', 'while': '\nThe ``while`` statement\n***********************\n\nThe ``while`` statement is used for repeated execution as long as an\nexpression is true:\n\n while_stmt ::= "while" expression ":" suite\n ["else" ":" suite]\n\nThis repeatedly tests the expression and, if it is true, executes the\nfirst suite; if the expression is false (which may be the first time\nit is tested) the suite of the ``else`` clause, if present, is\nexecuted and the loop terminates.\n\nA ``break`` statement executed in the first suite terminates the loop\nwithout executing the ``else`` clause\'s suite. A ``continue``\nstatement executed in the first suite skips the rest of the suite and\ngoes back to testing the expression.\n', 'with': '\nThe ``with`` statement\n**********************\n\nThe ``with`` statement is used to wrap the execution of a block with\nmethods defined by a context manager (see section *With Statement\nContext Managers*). This allows common\n``try``...``except``...``finally`` usage patterns to be encapsulated\nfor convenient reuse.\n\n with_stmt ::= "with" with_item ("," with_item)* ":" suite\n with_item ::= expression ["as" target]\n\nThe execution of the ``with`` statement with one "item" proceeds as\nfollows:\n\n1. The context expression (the expression given in the ``with_item``)\n is evaluated to obtain a context manager.\n\n2. The context manager\'s ``__exit__()`` is loaded for later use.\n\n3. The context manager\'s ``__enter__()`` method is invoked.\n\n4. If a target was included in the ``with`` statement, the return\n value from ``__enter__()`` is assigned to it.\n\n Note: The ``with`` statement guarantees that if the ``__enter__()``\n method returns without an error, then ``__exit__()`` will always\n be called. Thus, if an error occurs during the assignment to the\n target list, it will be treated the same as an error occurring\n within the suite would be. See step 6 below.\n\n5. The suite is executed.\n\n6. The context manager\'s ``__exit__()`` method is invoked. If an\n exception caused the suite to be exited, its type, value, and\n traceback are passed as arguments to ``__exit__()``. Otherwise,\n three ``None`` arguments are supplied.\n\n If the suite was exited due to an exception, and the return value\n from the ``__exit__()`` method was false, the exception is\n reraised. If the return value was true, the exception is\n suppressed, and execution continues with the statement following\n the ``with`` statement.\n\n If the suite was exited for any reason other than an exception, the\n return value from ``__exit__()`` is ignored, and execution proceeds\n at the normal location for the kind of exit that was taken.\n\nWith more than one item, the context managers are processed as if\nmultiple ``with`` statements were nested:\n\n with A() as a, B() as b:\n suite\n\nis equivalent to\n\n with A() as a:\n with B() as b:\n suite\n\nChanged in version 3.1: Support for multiple context expressions.\n\nSee also:\n\n **PEP 0343** - The "with" statement\n The specification, background, and examples for the Python\n ``with`` statement.\n', diff --git a/Lib/test/test_pydoc.py b/Lib/test/test_pydoc.py --- a/Lib/test/test_pydoc.py +++ b/Lib/test/test_pydoc.py @@ -3,6 +3,7 @@ import difflib import inspect import pydoc +import keyword import re import string import subprocess @@ -471,11 +472,17 @@ self.assertEqual(result, title) +class TestHelper(unittest.TestCase): + def test_keywords(self): + self.assertEqual(sorted(pydoc.Helper.keywords), + sorted(keyword.kwlist)) + def test_main(): test.support.run_unittest(PydocDocTest, TestDescriptions, PydocServerTest, PydocUrlHandlerTest, + TestHelper, ) if __name__ == "__main__": -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Apr 28 06:59:53 2011 From: python-checkins at python.org (ezio.melotti) Date: Thu, 28 Apr 2011 06:59:53 +0200 Subject: [Python-checkins] cpython (2.7): Backport test from #11926. Message-ID: http://hg.python.org/cpython/rev/ffd83aeb0b67 changeset: 69652:ffd83aeb0b67 branch: 2.7 parent: 69648:eb7c4526ccbf user: Ezio Melotti date: Thu Apr 28 07:59:33 2011 +0300 summary: Backport test from #11926. files: Lib/test/test_pydoc.py | 10 +++++++++- 1 files changed, 9 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_pydoc.py b/Lib/test/test_pydoc.py --- a/Lib/test/test_pydoc.py +++ b/Lib/test/test_pydoc.py @@ -6,6 +6,7 @@ import re import pydoc import inspect +import keyword import unittest import xml.etree import test.test_support @@ -351,9 +352,16 @@ self.assertIn('_asdict', helptext) +class TestHelper(unittest.TestCase): + def test_keywords(self): + self.assertEqual(sorted(pydoc.Helper.keywords), + sorted(keyword.kwlist)) + + def test_main(): test.test_support.run_unittest(PyDocDocTest, - TestDescriptions) + TestDescriptions, + TestHelper) if __name__ == "__main__": test_main() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Apr 28 09:32:16 2011 From: python-checkins at python.org (senthil.kumaran) Date: Thu, 28 Apr 2011 09:32:16 +0200 Subject: [Python-checkins] cpython (2.7): Fix closes issue10761: tarfile.extractall failure when symlinked files are Message-ID: http://hg.python.org/cpython/rev/0c8bc3a0130a changeset: 69653:0c8bc3a0130a branch: 2.7 user: Senthil Kumaran date: Thu Apr 28 15:30:31 2011 +0800 summary: Fix closes issue10761: tarfile.extractall failure when symlinked files are present. files: Lib/tarfile.py | 2 ++ Lib/test/test_tarfile.py | 27 +++++++++++++++++++++++++++ Misc/NEWS | 3 +++ 3 files changed, 32 insertions(+), 0 deletions(-) diff --git a/Lib/tarfile.py b/Lib/tarfile.py --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -2239,6 +2239,8 @@ if hasattr(os, "symlink") and hasattr(os, "link"): # For systems that support symbolic and hard links. if tarinfo.issym(): + if os.path.exists(targetpath): + os.unlink(targetpath) os.symlink(tarinfo.linkname, targetpath) else: # See extract(). diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py --- a/Lib/test/test_tarfile.py +++ b/Lib/test/test_tarfile.py @@ -843,6 +843,33 @@ finally: os.chdir(cwd) + def test_extractall_symlinks(self): + # Test if extractall works properly when tarfile contains symlinks + tempdir = os.path.join(TEMPDIR, "testsymlinks") + temparchive = os.path.join(TEMPDIR, "testsymlinks.tar") + os.mkdir(tempdir) + try: + source_file = os.path.join(tempdir,'source') + target_file = os.path.join(tempdir,'symlink') + with open(source_file,'w') as f: + f.write('something\n') + os.symlink(source_file, target_file) + tar = tarfile.open(temparchive,'w') + tar.add(source_file, arcname=os.path.basename(source_file)) + tar.add(target_file, arcname=os.path.basename(target_file)) + tar.close() + # Let's extract it to the location which contains the symlink + tar = tarfile.open(temparchive,'r') + # this should not raise OSError: [Errno 17] File exists + try: + tar.extractall(path=tempdir) + except OSError: + self.fail("extractall failed with symlinked files") + finally: + tar.close() + finally: + os.unlink(temparchive) + shutil.rmtree(tempdir) class StreamWriteTest(WriteTestBase): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -65,6 +65,9 @@ Library ------- +- Issue #10761: Fix tarfile.extractall failure when symlinked files are + present. Initial patch by Scott Leerssen. + - Issue #11763: don't use difflib in TestCase.assertMultiLineEqual if the strings are too long. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Apr 28 09:54:21 2011 From: python-checkins at python.org (senthil.kumaran) Date: Thu, 28 Apr 2011 09:54:21 +0200 Subject: [Python-checkins] cpython (3.1): Add tests for tarfile extractall feature when with symlinks Message-ID: http://hg.python.org/cpython/rev/4f9a289a1f6d changeset: 69654:4f9a289a1f6d branch: 3.1 parent: 69649:99d5542399a1 user: Senthil Kumaran date: Thu Apr 28 15:38:12 2011 +0800 summary: Add tests for tarfile extractall feature when with symlinks files: Lib/test/test_tarfile.py | 27 +++++++++++++++++++++++++++ 1 files changed, 27 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py --- a/Lib/test/test_tarfile.py +++ b/Lib/test/test_tarfile.py @@ -678,6 +678,33 @@ finally: shutil.rmtree(tempdir) + def test_extractall_symlinks(self): + # Test if extractall works properly when tarfile contains symlinks + tempdir = os.path.join(TEMPDIR, "testsymlinks") + temparchive = os.path.join(TEMPDIR, "testsymlinks.tar") + os.mkdir(tempdir) + try: + source_file = os.path.join(tempdir,'source') + target_file = os.path.join(tempdir,'symlink') + with open(source_file,'w') as f: + f.write('something\n') + os.symlink(source_file, target_file) + tar = tarfile.open(temparchive,'w') + tar.add(source_file) + tar.add(target_file) + tar.close() + # Let's extract it to the location which contains the symlink + tar = tarfile.open(temparchive,'r') + # this should not raise OSError: [Errno 17] File exists + try: + tar.extractall(path=tempdir) + except OSError: + self.fail("extractall failed with symlinked files") + finally: + tar.close() + finally: + os.unlink(temparchive) + shutil.rmtree(tempdir) class StreamWriteTest(WriteTestBase): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Apr 28 09:54:24 2011 From: python-checkins at python.org (senthil.kumaran) Date: Thu, 28 Apr 2011 09:54:24 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): merge from 3.1 Message-ID: http://hg.python.org/cpython/rev/492823e935b3 changeset: 69655:492823e935b3 branch: 3.2 parent: 69650:7b4c853aa07d parent: 69654:4f9a289a1f6d user: Senthil Kumaran date: Thu Apr 28 15:53:09 2011 +0800 summary: merge from 3.1 files: Lib/test/test_tarfile.py | 28 ++++++++++++++++++++++++++++ 1 files changed, 28 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py --- a/Lib/test/test_tarfile.py +++ b/Lib/test/test_tarfile.py @@ -982,6 +982,34 @@ self.assertEqual(t.name, cmp_path or path.replace(os.sep, "/")) + def test_extractall_symlinks(self): + # Test if extractall works properly when tarfile contains symlinks + tempdir = os.path.join(TEMPDIR, "testsymlinks") + temparchive = os.path.join(TEMPDIR, "testsymlinks.tar") + os.mkdir(tempdir) + try: + source_file = os.path.join(tempdir,'source') + target_file = os.path.join(tempdir,'symlink') + with open(source_file,'w') as f: + f.write('something\n') + os.symlink(source_file, target_file) + tar = tarfile.open(temparchive,'w') + tar.add(source_file) + tar.add(target_file) + tar.close() + # Let's extract it to the location which contains the symlink + tar = tarfile.open(temparchive,'r') + # this should not raise OSError: [Errno 17] File exists + try: + tar.extractall(path=tempdir) + except OSError: + self.fail("extractall failed with symlinked files") + finally: + tar.close() + finally: + os.unlink(temparchive) + shutil.rmtree(tempdir) + def test_pathnames(self): self._test_pathname("foo") self._test_pathname(os.path.join("foo", ".", "bar")) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Apr 28 09:54:26 2011 From: python-checkins at python.org (senthil.kumaran) Date: Thu, 28 Apr 2011 09:54:26 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): merge from 3.2 Message-ID: http://hg.python.org/cpython/rev/a66b074cf912 changeset: 69656:a66b074cf912 parent: 69651:0d8a6833f5be parent: 69655:492823e935b3 user: Senthil Kumaran date: Thu Apr 28 15:53:59 2011 +0800 summary: merge from 3.2 files: Lib/test/test_tarfile.py | 28 ++++++++++++++++++++++++++++ 1 files changed, 28 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py --- a/Lib/test/test_tarfile.py +++ b/Lib/test/test_tarfile.py @@ -982,6 +982,34 @@ self.assertEqual(t.name, cmp_path or path.replace(os.sep, "/")) + def test_extractall_symlinks(self): + # Test if extractall works properly when tarfile contains symlinks + tempdir = os.path.join(TEMPDIR, "testsymlinks") + temparchive = os.path.join(TEMPDIR, "testsymlinks.tar") + os.mkdir(tempdir) + try: + source_file = os.path.join(tempdir,'source') + target_file = os.path.join(tempdir,'symlink') + with open(source_file,'w') as f: + f.write('something\n') + os.symlink(source_file, target_file) + tar = tarfile.open(temparchive,'w') + tar.add(source_file) + tar.add(target_file) + tar.close() + # Let's extract it to the location which contains the symlink + tar = tarfile.open(temparchive,'r') + # this should not raise OSError: [Errno 17] File exists + try: + tar.extractall(path=tempdir) + except OSError: + self.fail("extractall failed with symlinked files") + finally: + tar.close() + finally: + os.unlink(temparchive) + shutil.rmtree(tempdir) + def test_pathnames(self): self._test_pathname("foo") self._test_pathname(os.path.join("foo", ".", "bar")) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Apr 28 11:00:16 2011 From: python-checkins at python.org (lukasz.langa) Date: Thu, 28 Apr 2011 11:00:16 +0200 Subject: [Python-checkins] cpython (3.2): Closes #11858: configparser.ExtendedInterpolation and section case. Message-ID: http://hg.python.org/cpython/rev/57c076ab4bbd changeset: 69657:57c076ab4bbd branch: 3.2 parent: 69655:492823e935b3 user: ?ukasz Langa date: Thu Apr 28 10:58:57 2011 +0200 summary: Closes #11858: configparser.ExtendedInterpolation and section case. Patch by ??? ?????. Thanks! files: Lib/configparser.py | 8 +- Lib/test/test_cfgparser.py | 70 ++++++++++++++++++++++++- 2 files changed, 72 insertions(+), 6 deletions(-) diff --git a/Lib/configparser.py b/Lib/configparser.py --- a/Lib/configparser.py +++ b/Lib/configparser.py @@ -481,17 +481,17 @@ if m is None: raise InterpolationSyntaxError(option, section, "bad interpolation variable reference %r" % rest) - path = parser.optionxform(m.group(1)).split(':') + path = m.group(1).split(':') rest = rest[m.end():] sect = section opt = option try: if len(path) == 1: - opt = path[0] + opt = parser.optionxform(path[0]) v = map[opt] elif len(path) == 2: sect = path[0] - opt = path[1] + opt = parser.optionxform(path[1]) v = parser.get(sect, opt, raw=True) else: raise InterpolationSyntaxError( @@ -1056,6 +1056,8 @@ if not optname: e = self._handle_error(e, fpname, lineno, line) optname = self.optionxform(optname.rstrip()) + if hasattr(self, '__ping__'): + import pdb; pdb.set_trace() if (self._strict and (sectname, optname) in elements_added): raise DuplicateOptionError(sectname, optname, diff --git a/Lib/test/test_cfgparser.py b/Lib/test/test_cfgparser.py --- a/Lib/test/test_cfgparser.py +++ b/Lib/test/test_cfgparser.py @@ -20,10 +20,16 @@ def values(self): return [i[1] for i in self.items()] - def iteritems(self): return iter(self.items()) - def iterkeys(self): return iter(self.keys()) + def iteritems(self): + return iter(self.items()) + + def iterkeys(self): + return iter(self.keys()) + + def itervalues(self): + return iter(self.values()) + __iter__ = iterkeys - def itervalues(self): return iter(self.values()) class CfgParserTestCaseClass(unittest.TestCase): @@ -986,6 +992,14 @@ config_class = configparser.ConfigParser interpolation = configparser.ExtendedInterpolation() default_section = 'common' + strict = True + + def fromstring(self, string, defaults=None, optionxform=None): + cf = self.newconfig(defaults) + if optionxform: + cf.optionxform = optionxform + cf.read_string(string) + return cf def test_extended_interpolation(self): cf = self.fromstring(textwrap.dedent(""" @@ -1070,6 +1084,56 @@ self.assertEqual(cm.exception.reference, 'dollars:${sick') self.assertEqual(cm.exception.args[2], '}') #rawval + def test_case_sensitivity_basic(self): + ini = textwrap.dedent(""" + [common] + optionlower = value + OptionUpper = Value + + [Common] + optionlower = a better ${common:optionlower} + OptionUpper = A Better ${common:OptionUpper} + + [random] + foolower = ${common:optionlower} redefined + FooUpper = ${Common:OptionUpper} Redefined + """).strip() + + cf = self.fromstring(ini) + eq = self.assertEqual + eq(cf['common']['optionlower'], 'value') + eq(cf['common']['OptionUpper'], 'Value') + eq(cf['Common']['optionlower'], 'a better value') + eq(cf['Common']['OptionUpper'], 'A Better Value') + eq(cf['random']['foolower'], 'value redefined') + eq(cf['random']['FooUpper'], 'A Better Value Redefined') + + def test_case_sensitivity_conflicts(self): + ini = textwrap.dedent(""" + [common] + option = value + Option = Value + + [Common] + option = a better ${common:option} + Option = A Better ${common:Option} + + [random] + foo = ${common:option} redefined + Foo = ${Common:Option} Redefined + """).strip() + with self.assertRaises(configparser.DuplicateOptionError): + cf = self.fromstring(ini) + + # raw options + cf = self.fromstring(ini, optionxform=lambda opt: opt) + eq = self.assertEqual + eq(cf['common']['option'], 'value') + eq(cf['common']['Option'], 'Value') + eq(cf['Common']['option'], 'a better value') + eq(cf['Common']['Option'], 'A Better Value') + eq(cf['random']['foo'], 'value redefined') + eq(cf['random']['Foo'], 'A Better Value Redefined') def test_other_errors(self): cf = self.fromstring(""" -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Apr 28 11:01:04 2011 From: python-checkins at python.org (senthil.kumaran) Date: Thu, 28 Apr 2011 11:01:04 +0200 Subject: [Python-checkins] cpython (2.7): skip the extractall test on platforms where os.symlink is not available. Message-ID: http://hg.python.org/cpython/rev/e19d2e3a3a58 changeset: 69658:e19d2e3a3a58 branch: 2.7 parent: 69653:0c8bc3a0130a user: Senthil Kumaran date: Thu Apr 28 17:00:19 2011 +0800 summary: skip the extractall test on platforms where os.symlink is not available. files: Lib/test/test_tarfile.py | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py --- a/Lib/test/test_tarfile.py +++ b/Lib/test/test_tarfile.py @@ -843,6 +843,7 @@ finally: os.chdir(cwd) + @unittest.skipUnless(hasattr(os, 'symlink'), "needs os.symlink") def test_extractall_symlinks(self): # Test if extractall works properly when tarfile contains symlinks tempdir = os.path.join(TEMPDIR, "testsymlinks") -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Apr 28 11:01:27 2011 From: python-checkins at python.org (lukasz.langa) Date: Thu, 28 Apr 2011 11:01:27 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merged solution for #11858 from 3.2. Message-ID: http://hg.python.org/cpython/rev/2afaef6cda8a changeset: 69659:2afaef6cda8a parent: 69656:a66b074cf912 parent: 69657:57c076ab4bbd user: ?ukasz Langa date: Thu Apr 28 11:01:18 2011 +0200 summary: Merged solution for #11858 from 3.2. files: Lib/configparser.py | 8 +- Lib/test/test_configparser.py | 70 ++++++++++++++++++++++- 2 files changed, 72 insertions(+), 6 deletions(-) diff --git a/Lib/configparser.py b/Lib/configparser.py --- a/Lib/configparser.py +++ b/Lib/configparser.py @@ -482,17 +482,17 @@ if m is None: raise InterpolationSyntaxError(option, section, "bad interpolation variable reference %r" % rest) - path = parser.optionxform(m.group(1)).split(':') + path = m.group(1).split(':') rest = rest[m.end():] sect = section opt = option try: if len(path) == 1: - opt = path[0] + opt = parser.optionxform(path[0]) v = map[opt] elif len(path) == 2: sect = path[0] - opt = path[1] + opt = parser.optionxform(path[1]) v = parser.get(sect, opt, raw=True) else: raise InterpolationSyntaxError( @@ -1057,6 +1057,8 @@ if not optname: e = self._handle_error(e, fpname, lineno, line) optname = self.optionxform(optname.rstrip()) + if hasattr(self, '__ping__'): + import pdb; pdb.set_trace() if (self._strict and (sectname, optname) in elements_added): raise DuplicateOptionError(sectname, optname, diff --git a/Lib/test/test_configparser.py b/Lib/test/test_configparser.py --- a/Lib/test/test_configparser.py +++ b/Lib/test/test_configparser.py @@ -20,10 +20,16 @@ def values(self): return [i[1] for i in self.items()] - def iteritems(self): return iter(self.items()) - def iterkeys(self): return iter(self.keys()) + def iteritems(self): + return iter(self.items()) + + def iterkeys(self): + return iter(self.keys()) + + def itervalues(self): + return iter(self.values()) + __iter__ = iterkeys - def itervalues(self): return iter(self.values()) class CfgParserTestCaseClass(unittest.TestCase): @@ -986,6 +992,14 @@ config_class = configparser.ConfigParser interpolation = configparser.ExtendedInterpolation() default_section = 'common' + strict = True + + def fromstring(self, string, defaults=None, optionxform=None): + cf = self.newconfig(defaults) + if optionxform: + cf.optionxform = optionxform + cf.read_string(string) + return cf def test_extended_interpolation(self): cf = self.fromstring(textwrap.dedent(""" @@ -1070,6 +1084,56 @@ self.assertEqual(cm.exception.reference, 'dollars:${sick') self.assertEqual(cm.exception.args[2], '}') #rawval + def test_case_sensitivity_basic(self): + ini = textwrap.dedent(""" + [common] + optionlower = value + OptionUpper = Value + + [Common] + optionlower = a better ${common:optionlower} + OptionUpper = A Better ${common:OptionUpper} + + [random] + foolower = ${common:optionlower} redefined + FooUpper = ${Common:OptionUpper} Redefined + """).strip() + + cf = self.fromstring(ini) + eq = self.assertEqual + eq(cf['common']['optionlower'], 'value') + eq(cf['common']['OptionUpper'], 'Value') + eq(cf['Common']['optionlower'], 'a better value') + eq(cf['Common']['OptionUpper'], 'A Better Value') + eq(cf['random']['foolower'], 'value redefined') + eq(cf['random']['FooUpper'], 'A Better Value Redefined') + + def test_case_sensitivity_conflicts(self): + ini = textwrap.dedent(""" + [common] + option = value + Option = Value + + [Common] + option = a better ${common:option} + Option = A Better ${common:Option} + + [random] + foo = ${common:option} redefined + Foo = ${Common:Option} Redefined + """).strip() + with self.assertRaises(configparser.DuplicateOptionError): + cf = self.fromstring(ini) + + # raw options + cf = self.fromstring(ini, optionxform=lambda opt: opt) + eq = self.assertEqual + eq(cf['common']['option'], 'value') + eq(cf['common']['Option'], 'Value') + eq(cf['Common']['option'], 'a better value') + eq(cf['Common']['Option'], 'A Better Value') + eq(cf['random']['foo'], 'value redefined') + eq(cf['random']['Foo'], 'A Better Value Redefined') def test_other_errors(self): cf = self.fromstring(""" -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Apr 28 11:09:18 2011 From: python-checkins at python.org (senthil.kumaran) Date: Thu, 28 Apr 2011 11:09:18 +0200 Subject: [Python-checkins] cpython (3.1): skip the extractall test on platforms where os.symlink is not available. Message-ID: http://hg.python.org/cpython/rev/7c307fd57021 changeset: 69660:7c307fd57021 branch: 3.1 parent: 69654:4f9a289a1f6d user: Senthil Kumaran date: Thu Apr 28 17:05:55 2011 +0800 summary: skip the extractall test on platforms where os.symlink is not available. files: Lib/test/test_tarfile.py | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py --- a/Lib/test/test_tarfile.py +++ b/Lib/test/test_tarfile.py @@ -249,6 +249,7 @@ data = open(os.path.join(TEMPDIR, "ustar/symtype"), "rb").read() self.assertEqual(md5sum(data), md5_regtype) + @unittest.skipUnless(hasattr(os,'symlink'), "needs os.symlink") def test_extractall(self): # Test if extractall() correctly restores directory permissions # and times (see issue1735). -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Apr 28 11:09:19 2011 From: python-checkins at python.org (senthil.kumaran) Date: Thu, 28 Apr 2011 11:09:19 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): merge from 3.1 Message-ID: http://hg.python.org/cpython/rev/08d097a21aae changeset: 69661:08d097a21aae branch: 3.2 parent: 69657:57c076ab4bbd parent: 69660:7c307fd57021 user: Senthil Kumaran date: Thu Apr 28 17:08:12 2011 +0800 summary: merge from 3.1 files: Lib/test/test_tarfile.py | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py --- a/Lib/test/test_tarfile.py +++ b/Lib/test/test_tarfile.py @@ -351,6 +351,7 @@ finally: tar.close() + @support.skip_unless_symlink def test_extractall(self): # Test if extractall() correctly restores directory permissions # and times (see issue1735). -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Apr 28 11:09:26 2011 From: python-checkins at python.org (senthil.kumaran) Date: Thu, 28 Apr 2011 11:09:26 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): merge from 3.2 Message-ID: http://hg.python.org/cpython/rev/b9b8c8032080 changeset: 69662:b9b8c8032080 parent: 69659:2afaef6cda8a parent: 69661:08d097a21aae user: Senthil Kumaran date: Thu Apr 28 17:08:41 2011 +0800 summary: merge from 3.2 files: Lib/test/test_tarfile.py | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py --- a/Lib/test/test_tarfile.py +++ b/Lib/test/test_tarfile.py @@ -351,6 +351,7 @@ finally: tar.close() + @support.skip_unless_symlink def test_extractall(self): # Test if extractall() correctly restores directory permissions # and times (see issue1735). -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Apr 28 12:03:12 2011 From: python-checkins at python.org (lukasz.langa) Date: Thu, 28 Apr 2011 12:03:12 +0200 Subject: [Python-checkins] cpython (3.2): Style updates for the #11670 solution after post-commit review by Ezio Melotti: Message-ID: http://hg.python.org/cpython/rev/1bbda00bbe78 changeset: 69663:1bbda00bbe78 branch: 3.2 parent: 69661:08d097a21aae user: ?ukasz Langa date: Thu Apr 28 12:02:05 2011 +0200 summary: Style updates for the #11670 solution after post-commit review by Ezio Melotti: http://mail.python.org/pipermail/python-checkins/2011-April/104688.html Thanks! files: Doc/library/configparser.rst | 40 ++++++++++------------- Lib/test/test_cfgparser.py | 14 ++++---- 2 files changed, 24 insertions(+), 30 deletions(-) diff --git a/Doc/library/configparser.rst b/Doc/library/configparser.rst --- a/Doc/library/configparser.rst +++ b/Doc/library/configparser.rst @@ -975,7 +975,7 @@ .. method:: read_file(f, source=None) Read and parse configuration data from *f* which must be an iterable - yielding Unicode strings (for example any file object). + yielding Unicode strings (for example files opened in text mode). Optional argument *source* specifies the name of the file being read. If not given and *f* has a :attr:`name` attribute, that is used for @@ -984,28 +984,6 @@ .. versionadded:: 3.2 Replaces :meth:`readfp`. - .. note:: - - Prior to Python 3.2, :meth:`readfp` consumed lines from the file-like - argument by calling its :meth:`~file.readline` method. For existing code - calling :meth:`readfp` with arguments which don't support iteration, - the following generator may be used as a wrapper around the file-like - object:: - - def readline_generator(f): - line = f.readline() - while line != '': - yield line - line = f.readline() - - Before:: - - parser.readfp(f) - - After:: - - parser.read_file(readline_generator(f)) - .. method:: read_string(string, source='') Parse configuration data from a string. @@ -1142,6 +1120,22 @@ .. deprecated:: 3.2 Use :meth:`read_file` instead. + .. versionchanged:: 3.2 + :meth:`readfp` now iterates on *f* instead of calling ``f.readline()``. + + For existing code calling :meth:`readfp` with arguments which don't + support iteration, the following generator may be used as a wrapper + around the file-like object:: + + def readline_generator(f): + line = f.readline() + while line: + yield line + line = f.readline() + + Instead of ``parser.readfp(f)`` use + ``parser.read_file(readline_generator(f))``. + .. data:: MAX_INTERPOLATION_DEPTH diff --git a/Lib/test/test_cfgparser.py b/Lib/test/test_cfgparser.py --- a/Lib/test/test_cfgparser.py +++ b/Lib/test/test_cfgparser.py @@ -1316,7 +1316,7 @@ def readline_generator(f): """As advised in Doc/library/configparser.rst.""" line = f.readline() - while line != '': + while line: yield line line = f.readline() @@ -1327,8 +1327,8 @@ parser = configparser.ConfigParser() with open(file_path) as f: parser.read_file(f) - self.assertTrue("Foo Bar" in parser) - self.assertTrue("foo" in parser["Foo Bar"]) + self.assertIn("Foo Bar", parser) + self.assertIn("foo", parser["Foo Bar"]) self.assertEqual(parser["Foo Bar"]["foo"], "newbar") def test_iterable(self): @@ -1337,8 +1337,8 @@ foo=newbar""").strip().split('\n') parser = configparser.ConfigParser() parser.read_file(lines) - self.assertTrue("Foo Bar" in parser) - self.assertTrue("foo" in parser["Foo Bar"]) + self.assertIn("Foo Bar", parser) + self.assertIn("foo", parser["Foo Bar"]) self.assertEqual(parser["Foo Bar"]["foo"], "newbar") def test_readline_generator(self): @@ -1347,8 +1347,8 @@ with self.assertRaises(TypeError): parser.read_file(FakeFile()) parser.read_file(readline_generator(FakeFile())) - self.assertTrue("Foo Bar" in parser) - self.assertTrue("foo" in parser["Foo Bar"]) + self.assertIn("Foo Bar", parser) + self.assertIn("foo", parser["Foo Bar"]) self.assertEqual(parser["Foo Bar"]["foo"], "newbar") -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Apr 28 12:03:13 2011 From: python-checkins at python.org (lukasz.langa) Date: Thu, 28 Apr 2011 12:03:13 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merged styling updates for #11670 from 3.2. Message-ID: http://hg.python.org/cpython/rev/339cd1d9b21a changeset: 69664:339cd1d9b21a parent: 69662:b9b8c8032080 parent: 69663:1bbda00bbe78 user: ?ukasz Langa date: Thu Apr 28 12:02:58 2011 +0200 summary: Merged styling updates for #11670 from 3.2. files: Doc/library/configparser.rst | 40 +++++++++------------- Lib/test/test_configparser.py | 14 ++++---- 2 files changed, 24 insertions(+), 30 deletions(-) diff --git a/Doc/library/configparser.rst b/Doc/library/configparser.rst --- a/Doc/library/configparser.rst +++ b/Doc/library/configparser.rst @@ -975,7 +975,7 @@ .. method:: read_file(f, source=None) Read and parse configuration data from *f* which must be an iterable - yielding Unicode strings (for example any file object). + yielding Unicode strings (for example files opened in text mode). Optional argument *source* specifies the name of the file being read. If not given and *f* has a :attr:`name` attribute, that is used for @@ -984,28 +984,6 @@ .. versionadded:: 3.2 Replaces :meth:`readfp`. - .. note:: - - Prior to Python 3.2, :meth:`readfp` consumed lines from the file-like - argument by calling its :meth:`~file.readline` method. For existing code - calling :meth:`readfp` with arguments which don't support iteration, - the following generator may be used as a wrapper around the file-like - object:: - - def readline_generator(f): - line = f.readline() - while line != '': - yield line - line = f.readline() - - Before:: - - parser.readfp(f) - - After:: - - parser.read_file(readline_generator(f)) - .. method:: read_string(string, source='') Parse configuration data from a string. @@ -1142,6 +1120,22 @@ .. deprecated:: 3.2 Use :meth:`read_file` instead. + .. versionchanged:: 3.2 + :meth:`readfp` now iterates on *f* instead of calling ``f.readline()``. + + For existing code calling :meth:`readfp` with arguments which don't + support iteration, the following generator may be used as a wrapper + around the file-like object:: + + def readline_generator(f): + line = f.readline() + while line: + yield line + line = f.readline() + + Instead of ``parser.readfp(f)`` use + ``parser.read_file(readline_generator(f))``. + .. data:: MAX_INTERPOLATION_DEPTH diff --git a/Lib/test/test_configparser.py b/Lib/test/test_configparser.py --- a/Lib/test/test_configparser.py +++ b/Lib/test/test_configparser.py @@ -1316,7 +1316,7 @@ def readline_generator(f): """As advised in Doc/library/configparser.rst.""" line = f.readline() - while line != '': + while line: yield line line = f.readline() @@ -1327,8 +1327,8 @@ parser = configparser.ConfigParser() with open(file_path) as f: parser.read_file(f) - self.assertTrue("Foo Bar" in parser) - self.assertTrue("foo" in parser["Foo Bar"]) + self.assertIn("Foo Bar", parser) + self.assertIn("foo", parser["Foo Bar"]) self.assertEqual(parser["Foo Bar"]["foo"], "newbar") def test_iterable(self): @@ -1337,8 +1337,8 @@ foo=newbar""").strip().split('\n') parser = configparser.ConfigParser() parser.read_file(lines) - self.assertTrue("Foo Bar" in parser) - self.assertTrue("foo" in parser["Foo Bar"]) + self.assertIn("Foo Bar", parser) + self.assertIn("foo", parser["Foo Bar"]) self.assertEqual(parser["Foo Bar"]["foo"], "newbar") def test_readline_generator(self): @@ -1347,8 +1347,8 @@ with self.assertRaises(TypeError): parser.read_file(FakeFile()) parser.read_file(readline_generator(FakeFile())) - self.assertTrue("Foo Bar" in parser) - self.assertTrue("foo" in parser["Foo Bar"]) + self.assertIn("Foo Bar", parser) + self.assertIn("foo", parser["Foo Bar"]) self.assertEqual(parser["Foo Bar"]["foo"], "newbar") -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Apr 28 13:17:40 2011 From: python-checkins at python.org (vinay.sajip) Date: Thu, 28 Apr 2011 13:17:40 +0200 Subject: [Python-checkins] cpython: Improved test_logging coverage. Message-ID: http://hg.python.org/cpython/rev/b452559eee71 changeset: 69665:b452559eee71 user: Vinay Sajip date: Thu Apr 28 12:04:58 2011 +0100 summary: Improved test_logging coverage. files: Lib/logging/__init__.py | 2 +- Lib/logging/handlers.py | 4 +- Lib/test/test_logging.py | 66 ++++++++++++++++++++++++++- 3 files changed, 65 insertions(+), 7 deletions(-) diff --git a/Lib/logging/__init__.py b/Lib/logging/__init__.py --- a/Lib/logging/__init__.py +++ b/Lib/logging/__init__.py @@ -296,7 +296,7 @@ # for an example try: self.processName = mp.current_process().name - except StandardError: + except StandardError: #pragma: no cover pass if logProcesses and hasattr(os, 'getpid'): self.process = os.getpid() diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py --- a/Lib/logging/handlers.py +++ b/Lib/logging/handlers.py @@ -490,14 +490,14 @@ try: if hasattr(self.sock, "sendall"): self.sock.sendall(s) - else: + else: #pragma: no cover sentsofar = 0 left = len(s) while left > 0: sent = self.sock.send(s[sentsofar:]) sentsofar = sentsofar + sent left = left - sent - except socket.error: + except socket.error: #pragma: no cover self.sock.close() self.sock = None # so we can call createSocket next time 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 @@ -519,8 +519,17 @@ os.unlink(fn) h = logging.handlers.WatchedFileHandler(fn, delay=True) if existing: - self.assertNotEqual(h.dev, -1) - self.assertNotEqual(h.ino, -1) + dev, ino = h.dev, h.ino + self.assertNotEqual(dev, -1) + self.assertNotEqual(ino, -1) + r = logging.makeLogRecord({'msg': 'Test'}) + h.handle(r) + # Now remove the file. + os.unlink(fn) + self.assertFalse(os.path.exists(fn)) + # The next call should recreate the file. + h.handle(r) + self.assertTrue(os.path.exists(fn)) else: self.assertEqual(h.dev, -1) self.assertEqual(h.ino, -1) @@ -1045,8 +1054,9 @@ def tearDown(self): """Shutdown the TCP server.""" try: - self.tcpserver.abort = True - del self.tcpserver + if hasattr(self, 'tcpserver'): + self.tcpserver.abort = True + del self.tcpserver self.root_logger.removeHandler(self.sock_hdlr) self.sock_hdlr.close() for thread in self.threads: @@ -1068,6 +1078,22 @@ logger.debug("eggs") self.assertEqual(self.get_output(), "spam\neggs\n") + def test_noserver(self): + # Kill the server + self.tcpserver.abort = True + del self.tcpserver + for thread in self.threads: + thread.join(2.0) + #The logging call should try to connect, which should fail + try: + raise RuntimeError('Deliberate mistake') + except RuntimeError: + self.root_logger.exception('Never sent') + self.root_logger.error('Never sent, either') + now = time.time() + self.assertTrue(self.sock_hdlr.retryTime > now) + time.sleep(self.sock_hdlr.retryTime - now + 0.001) + self.root_logger.error('Nor this') class MemoryTest(BaseTest): @@ -2613,6 +2639,38 @@ r.removeHandler(h) h.close() + def test_multiprocessing(self): + r = logging.makeLogRecord({}) + self.assertEqual(r.processName, 'MainProcess') + import multiprocessing as mp + r = logging.makeLogRecord({}) + self.assertEqual(r.processName, mp.current_process().name) + + def test_optional(self): + r = logging.makeLogRecord({}) + NOT_NONE = self.assertIsNotNone + NOT_NONE(r.thread) + NOT_NONE(r.threadName) + NOT_NONE(r.process) + NOT_NONE(r.processName) + log_threads = logging.logThreads + log_processes = logging.logProcesses + log_multiprocessing = logging.logMultiprocessing + try: + logging.logThreads = False + logging.logProcesses = False + logging.logMultiprocessing = False + r = logging.makeLogRecord({}) + NONE = self.assertIsNone + NONE(r.thread) + NONE(r.threadName) + NONE(r.process) + NONE(r.processName) + finally: + logging.logThreads = log_threads + logging.logProcesses = log_processes + logging.logMultiprocessing = log_multiprocessing + class BasicConfigTest(unittest.TestCase): """Test suite for logging.basicConfig.""" -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Apr 28 16:02:40 2011 From: python-checkins at python.org (lukasz.langa) Date: Thu, 28 Apr 2011 16:02:40 +0200 Subject: [Python-checkins] cpython (3.2): Added Yuxiao Zeng for finding and resolving #11858. Thanks! Message-ID: http://hg.python.org/cpython/rev/17b4378689e6 changeset: 69666:17b4378689e6 branch: 3.2 parent: 69663:1bbda00bbe78 user: ?ukasz Langa date: Thu Apr 28 16:00:57 2011 +0200 summary: Added Yuxiao Zeng for finding and resolving #11858. Thanks! files: Misc/ACKS | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -971,6 +971,7 @@ Artur Zaprzala Mike Zarnstorff Siebren van der Zee +Yuxiao Zeng Uwe Zessin Kai Zhu Tarek Ziad? -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Apr 28 16:02:44 2011 From: python-checkins at python.org (lukasz.langa) Date: Thu, 28 Apr 2011 16:02:44 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merged ACKS from 3.2: added Yuxiao Zeng Message-ID: http://hg.python.org/cpython/rev/062ca988cbf6 changeset: 69667:062ca988cbf6 parent: 69665:b452559eee71 parent: 69666:17b4378689e6 user: ?ukasz Langa date: Thu Apr 28 16:02:30 2011 +0200 summary: Merged ACKS from 3.2: added Yuxiao Zeng files: Misc/ACKS | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -979,6 +979,7 @@ Artur Zaprzala Mike Zarnstorff Siebren van der Zee +Yuxiao Zeng Uwe Zessin Kai Zhu Tarek Ziad? -- Repository URL: http://hg.python.org/cpython From merwok at netwok.org Thu Apr 28 16:20:06 2011 From: merwok at netwok.org (=?UTF-8?B?w4lyaWMgQXJhdWpv?=) Date: Thu, 28 Apr 2011 16:20:06 +0200 Subject: [Python-checkins] cpython (2.7): Fix closes issue10761: tarfile.extractall failure when symlinked files are In-Reply-To: References: Message-ID: <4DB97796.8010204@netwok.org> Hi, I?m still educating myself about concurrency and race conditions, so I hope my na?ve question won?t be just a waste of time. Here it is: > http://hg.python.org/cpython/rev/0c8bc3a0130a > user: Senthil Kumaran > summary: > Fix closes issue10761: tarfile.extractall failure when symlinked files are present. > diff --git a/Lib/tarfile.py b/Lib/tarfile.py > --- a/Lib/tarfile.py > +++ b/Lib/tarfile.py > @@ -2239,6 +2239,8 @@ > if hasattr(os, "symlink") and hasattr(os, "link"): > # For systems that support symbolic and hard links. > if tarinfo.issym(): > + if os.path.exists(targetpath): > + os.unlink(targetpath) Is there a race condition here? Thanks Regards From merwok at netwok.org Thu Apr 28 16:22:02 2011 From: merwok at netwok.org (=?UTF-8?B?w4lyaWMgQXJhdWpv?=) Date: Thu, 28 Apr 2011 16:22:02 +0200 Subject: [Python-checkins] cpython (3.2): Closes #11858: configparser.ExtendedInterpolation and section case. In-Reply-To: References: Message-ID: <4DB9780A.30204@netwok.org> Hi, > http://hg.python.org/cpython/rev/57c076ab4bbd > user: ?ukasz Langa > --- a/Lib/test/test_cfgparser.py > +++ b/Lib/test/test_cfgparser.py > @@ -20,10 +20,16 @@ > def values(self): > return [i[1] for i in self.items()] > > - def iteritems(self): return iter(self.items()) > - def iterkeys(self): return iter(self.keys()) > + def iteritems(self): > + return iter(self.items()) > + > + def iterkeys(self): > + return iter(self.keys()) > + > + def itervalues(self): > + return iter(self.values()) > + The dict methods in that subclass could probably be cleaned up. Regards From merwok at netwok.org Thu Apr 28 16:22:46 2011 From: merwok at netwok.org (=?UTF-8?B?w4lyaWMgQXJhdWpv?=) Date: Thu, 28 Apr 2011 16:22:46 +0200 Subject: [Python-checkins] cpython: Refined time test in test_logging. In-Reply-To: References: Message-ID: <4DB97836.3090004@netwok.org> Hi, > http://hg.python.org/cpython/rev/5185e1d91f3d > user: Vinay Sajip > summary: > Refined time test in test_logging. > +ZERO = datetime.timedelta(0) > + > +class UTC(datetime.tzinfo): > + def utcoffset(self, dt): > + return ZERO > + > + dst = utcoffset > + > + def tzname(self, dt): > + return 'UTC' > + > +utc = UTC() Any reason not to use datetime.datetime.utc here? Regards From python-checkins at python.org Thu Apr 28 17:04:41 2011 From: python-checkins at python.org (lukasz.langa) Date: Thu, 28 Apr 2011 17:04:41 +0200 Subject: [Python-checkins] cpython (3.2): Closes #11324: ConfigParser(interpolation=None) doesn't work. Message-ID: http://hg.python.org/cpython/rev/32031e33d793 changeset: 69668:32031e33d793 branch: 3.2 parent: 69666:17b4378689e6 user: ?ukasz Langa date: Thu Apr 28 17:03:45 2011 +0200 summary: Closes #11324: ConfigParser(interpolation=None) doesn't work. Initial patches by Tobias Brink. Thanks! files: Lib/configparser.py | 9 +++-- Lib/test/test_cfgparser.py | 38 ++++++++++++++++++++++++++ Misc/ACKS | 1 + 3 files changed, 44 insertions(+), 4 deletions(-) diff --git a/Lib/configparser.py b/Lib/configparser.py --- a/Lib/configparser.py +++ b/Lib/configparser.py @@ -623,11 +623,12 @@ self._strict = strict self._allow_no_value = allow_no_value self._empty_lines_in_values = empty_lines_in_values - if interpolation is _UNSET: + self.default_section=default_section + self._interpolation = interpolation + if self._interpolation is _UNSET: self._interpolation = self._DEFAULT_INTERPOLATION - else: - self._interpolation = interpolation - self.default_section=default_section + if self._interpolation is None: + self._interpolation = Interpolation() def defaults(self): return self._defaults diff --git a/Lib/test/test_cfgparser.py b/Lib/test/test_cfgparser.py --- a/Lib/test/test_cfgparser.py +++ b/Lib/test/test_cfgparser.py @@ -864,6 +864,43 @@ cf = self.newconfig() self.assertRaises(ValueError, cf.add_section, self.default_section) + +class ConfigParserTestCaseNoInterpolation(BasicTestCase): + config_class = configparser.ConfigParser + interpolation = None + ini = textwrap.dedent(""" + [numbers] + one = 1 + two = %(one)s * 2 + three = ${common:one} * 3 + + [hexen] + sixteen = ${numbers:two} * 8 + """).strip() + + def assertMatchesIni(self, cf): + self.assertEqual(cf['numbers']['one'], '1') + self.assertEqual(cf['numbers']['two'], '%(one)s * 2') + self.assertEqual(cf['numbers']['three'], '${common:one} * 3') + self.assertEqual(cf['hexen']['sixteen'], '${numbers:two} * 8') + + def test_no_interpolation(self): + cf = self.fromstring(self.ini) + self.assertMatchesIni(cf) + + def test_empty_case(self): + cf = self.newconfig() + self.assertIsNone(cf.read_string("")) + + def test_none_as_default_interpolation(self): + class CustomConfigParser(configparser.ConfigParser): + _DEFAULT_INTERPOLATION = None + + cf = CustomConfigParser() + cf.read_string(self.ini) + self.assertMatchesIni(cf) + + class ConfigParserTestCaseLegacyInterpolation(ConfigParserTestCase): config_class = configparser.ConfigParser interpolation = configparser.LegacyInterpolation() @@ -1444,6 +1481,7 @@ ConfigParserTestCaseNoValue, ConfigParserTestCaseExtendedInterpolation, ConfigParserTestCaseLegacyInterpolation, + ConfigParserTestCaseNoInterpolation, ConfigParserTestCaseTrickyFile, MultilineValuesTestCase, RawConfigParserTestCase, diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -113,6 +113,7 @@ Brian Brazil Dave Brennan Tom Bridgman +Tobias Brink Richard Brodie Michael Broghton Daniel Brotsky -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Apr 28 17:04:45 2011 From: python-checkins at python.org (lukasz.langa) Date: Thu, 28 Apr 2011 17:04:45 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merged solution for #11324 from 3.2. Message-ID: http://hg.python.org/cpython/rev/de7dc59260b1 changeset: 69669:de7dc59260b1 parent: 69667:062ca988cbf6 parent: 69668:32031e33d793 user: ?ukasz Langa date: Thu Apr 28 17:04:25 2011 +0200 summary: Merged solution for #11324 from 3.2. files: Lib/configparser.py | 9 +++-- Lib/test/test_configparser.py | 38 +++++++++++++++++++++++ Misc/ACKS | 1 + 3 files changed, 44 insertions(+), 4 deletions(-) diff --git a/Lib/configparser.py b/Lib/configparser.py --- a/Lib/configparser.py +++ b/Lib/configparser.py @@ -624,11 +624,12 @@ self._strict = strict self._allow_no_value = allow_no_value self._empty_lines_in_values = empty_lines_in_values - if interpolation is _UNSET: + self.default_section=default_section + self._interpolation = interpolation + if self._interpolation is _UNSET: self._interpolation = self._DEFAULT_INTERPOLATION - else: - self._interpolation = interpolation - self.default_section=default_section + if self._interpolation is None: + self._interpolation = Interpolation() def defaults(self): return self._defaults diff --git a/Lib/test/test_configparser.py b/Lib/test/test_configparser.py --- a/Lib/test/test_configparser.py +++ b/Lib/test/test_configparser.py @@ -864,6 +864,43 @@ cf = self.newconfig() self.assertRaises(ValueError, cf.add_section, self.default_section) + +class ConfigParserTestCaseNoInterpolation(BasicTestCase): + config_class = configparser.ConfigParser + interpolation = None + ini = textwrap.dedent(""" + [numbers] + one = 1 + two = %(one)s * 2 + three = ${common:one} * 3 + + [hexen] + sixteen = ${numbers:two} * 8 + """).strip() + + def assertMatchesIni(self, cf): + self.assertEqual(cf['numbers']['one'], '1') + self.assertEqual(cf['numbers']['two'], '%(one)s * 2') + self.assertEqual(cf['numbers']['three'], '${common:one} * 3') + self.assertEqual(cf['hexen']['sixteen'], '${numbers:two} * 8') + + def test_no_interpolation(self): + cf = self.fromstring(self.ini) + self.assertMatchesIni(cf) + + def test_empty_case(self): + cf = self.newconfig() + self.assertIsNone(cf.read_string("")) + + def test_none_as_default_interpolation(self): + class CustomConfigParser(configparser.ConfigParser): + _DEFAULT_INTERPOLATION = None + + cf = CustomConfigParser() + cf.read_string(self.ini) + self.assertMatchesIni(cf) + + class ConfigParserTestCaseLegacyInterpolation(ConfigParserTestCase): config_class = configparser.ConfigParser interpolation = configparser.LegacyInterpolation() @@ -1444,6 +1481,7 @@ ConfigParserTestCaseNoValue, ConfigParserTestCaseExtendedInterpolation, ConfigParserTestCaseLegacyInterpolation, + ConfigParserTestCaseNoInterpolation, ConfigParserTestCaseTrickyFile, MultilineValuesTestCase, RawConfigParserTestCase, diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -115,6 +115,7 @@ Brian Brazil Dave Brennan Tom Bridgman +Tobias Brink Richard Brodie Michael Broghton Daniel Brotsky -- Repository URL: http://hg.python.org/cpython From nadeem.vawda at gmail.com Thu Apr 28 17:40:05 2011 From: nadeem.vawda at gmail.com (Nadeem Vawda) Date: Thu, 28 Apr 2011 17:40:05 +0200 Subject: [Python-checkins] [Python-Dev] cpython (2.7): Fix closes issue10761: tarfile.extractall failure when symlinked files are In-Reply-To: <20110428144450.GB2699@kevin> References: <4DB97796.8010204@netwok.org> <20110428144450.GB2699@kevin> Message-ID: On Thu, Apr 28, 2011 at 4:44 PM, Senthil Kumaran wrote: > On Thu, Apr 28, 2011 at 04:20:06PM +0200, ?ric Araujo wrote: >> > if hasattr(os, "symlink") and hasattr(os, "link"): >> > # For systems that support symbolic and hard links. >> > if tarinfo.issym(): >> > + if os.path.exists(targetpath): >> > + os.unlink(targetpath) >> >> Is there a race condition here? > > The lock to avoid race conditions (if you were thinking along those > lines) would usually be implemented at the higher level code which is > using extractall in threads. > > Checking that no one else is accessing the file before unlinking may > not be suitable for the library method and of course, we cannot check > if someone is waiting to act on that file. I think ?ric is referring to the possibility of another process creating or deleting targetpath between the calls to os.path.exists() and os.unlink(). This would result in symlink() or unlink() raising an exception. The deletion case could be handled like this: if tarinfo.issym(): + try: + os.unlink(targetpath) + except OSError as e: + if e.errno != errno.ENOENT: + raise os.symlink(tarinfo.linkname, targetpath) I'm not sure what the best way of handling the creation case is. The obvious solution would be to try the above code in a loop, repeating until we succeed (or fail for a different reason), but this would not be guaranteed to terminate. Cheers, Nadeem From python-checkins at python.org Thu Apr 28 17:41:24 2011 From: python-checkins at python.org (lukasz.langa) Date: Thu, 28 Apr 2011 17:41:24 +0200 Subject: [Python-checkins] cpython (2.6): Closes #11786: ConfigParser.[Raw]ConfigParser optionxform(). Message-ID: http://hg.python.org/cpython/rev/c7ce67c9237a changeset: 69670:c7ce67c9237a branch: 2.6 parent: 69410:4bd47815e6c5 user: ?ukasz Langa date: Thu Apr 28 17:27:59 2011 +0200 summary: Closes #11786: ConfigParser.[Raw]ConfigParser optionxform(). files: Doc/library/configparser.rst | 12 +++++++----- 1 files changed, 7 insertions(+), 5 deletions(-) diff --git a/Doc/library/configparser.rst b/Doc/library/configparser.rst --- a/Doc/library/configparser.rst +++ b/Doc/library/configparser.rst @@ -79,9 +79,12 @@ The basic configuration object. When *defaults* is given, it is initialized into the dictionary of intrinsic defaults. When *dict_type* is given, it will be used to create the dictionary objects for the list of sections, for the - options within a section, and for the default values. This class does not + options within a section, and for the default values. This class does not support the magical interpolation behavior. + All option names are passed through the :meth:`optionxform` method. Its + default implementation converts option names to lower case. + .. versionadded:: 2.3 .. versionchanged:: 2.6 @@ -98,10 +101,9 @@ *defaults*. All option names used in interpolation will be passed through the - :meth:`optionxform` method just like any other option name reference. For - example, using the default implementation of :meth:`optionxform` (which converts - option names to lower case), the values ``foo %(bar)s`` and ``foo %(BAR)s`` are - equivalent. + :meth:`optionxform` method just like any other option name reference. Using + the default implementation of :meth:`optionxform`, the values ``foo %(bar)s`` + and ``foo %(BAR)s`` are equivalent. .. class:: SafeConfigParser([defaults[, dict_type]]) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Apr 28 17:41:25 2011 From: python-checkins at python.org (lukasz.langa) Date: Thu, 28 Apr 2011 17:41:25 +0200 Subject: [Python-checkins] cpython (merge 2.6 -> 2.7): Merged solution for #11786 from 2.6 Message-ID: http://hg.python.org/cpython/rev/a6b772599594 changeset: 69671:a6b772599594 branch: 2.7 parent: 69658:e19d2e3a3a58 parent: 69670:c7ce67c9237a user: ?ukasz Langa date: Thu Apr 28 17:40:19 2011 +0200 summary: Merged solution for #11786 from 2.6 files: Doc/library/configparser.rst | 10 ++++++---- 1 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Doc/library/configparser.rst b/Doc/library/configparser.rst --- a/Doc/library/configparser.rst +++ b/Doc/library/configparser.rst @@ -96,6 +96,9 @@ This class does not support the magical interpolation behavior. + All option names are passed through the :meth:`optionxform` method. Its + default implementation converts option names to lower case. + .. versionadded:: 2.3 .. versionchanged:: 2.6 @@ -116,10 +119,9 @@ *defaults*. All option names used in interpolation will be passed through the - :meth:`optionxform` method just like any other option name reference. For - example, using the default implementation of :meth:`optionxform` (which converts - option names to lower case), the values ``foo %(bar)s`` and ``foo %(BAR)s`` are - equivalent. + :meth:`optionxform` method just like any other option name reference. Using + the default implementation of :meth:`optionxform`, the values ``foo %(bar)s`` + and ``foo %(BAR)s`` are equivalent. .. versionadded:: 2.3 -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Thu Apr 28 17:44:51 2011 From: solipsis at pitrou.net (Antoine Pitrou) Date: Thu, 28 Apr 2011 17:44:51 +0200 Subject: [Python-checkins] [Python-Dev] cpython (2.7): Fix closes issue10761: tarfile.extractall failure when symlinked files are References: <4DB97796.8010204@netwok.org> <20110428144450.GB2699@kevin> Message-ID: <20110428174451.5a388d79@pitrou.net> On Thu, 28 Apr 2011 17:40:05 +0200 Nadeem Vawda wrote: > > The deletion case could be handled like this: > > if tarinfo.issym(): > + try: > + os.unlink(targetpath) > + except OSError as e: > + if e.errno != errno.ENOENT: > + raise > os.symlink(tarinfo.linkname, targetpath) Someone can still create "targetpath" between the calls to unlink() and symlink() though. Regards Antoine. From python-checkins at python.org Thu Apr 28 19:24:53 2011 From: python-checkins at python.org (antoine.pitrou) Date: Thu, 28 Apr 2011 19:24:53 +0200 Subject: [Python-checkins] cpython: Issue #11811: Factor out detection of IPv6 support on the current host Message-ID: http://hg.python.org/cpython/rev/0518f32cb747 changeset: 69672:0518f32cb747 parent: 69669:de7dc59260b1 user: Antoine Pitrou date: Thu Apr 28 19:18:10 2011 +0200 summary: Issue #11811: Factor out detection of IPv6 support on the current host and make it available as `test.support.IPV6_ENABLED`. Patch by Charles-Fran?ois Natali. files: Lib/test/support.py | 30 +++++++++++++++++++++------- Lib/test/test_ftplib.py | 2 +- Lib/test/test_socket.py | 15 +------------- Misc/NEWS | 4 +++ 4 files changed, 28 insertions(+), 23 deletions(-) diff --git a/Lib/test/support.py b/Lib/test/support.py --- a/Lib/test/support.py +++ b/Lib/test/support.py @@ -33,16 +33,15 @@ "verbose", "use_resources", "max_memuse", "record_original_stdout", "get_original_stdout", "unload", "unlink", "rmtree", "forget", "is_resource_enabled", "requires", "find_unused_port", "bind_port", - "is_jython", "TESTFN", "HOST", "SAVEDCWD", "temp_cwd", + "IPV6_ENABLED", "is_jython", "TESTFN", "HOST", "SAVEDCWD", "temp_cwd", "findfile", "sortdict", "check_syntax_error", "open_urlresource", "check_warnings", "CleanImport", "EnvironmentVarGuard", - "TransientResource", "captured_output", "captured_stdout", - "time_out", "socket_peer_reset", "ioerror_peer_reset", - "run_with_locale", 'temp_umask', "transient_internet", - "set_memlimit", "bigmemtest", "bigaddrspacetest", "BasicTestRunner", - "run_unittest", "run_doctest", "threading_setup", "threading_cleanup", - "reap_children", "cpython_only", "check_impl_detail", "get_attribute", - "swap_item", "swap_attr", "requires_IEEE_754", + "TransientResource", "captured_output", "captured_stdout", "time_out", + "socket_peer_reset", "ioerror_peer_reset", "run_with_locale", 'temp_umask', + "transient_internet", "set_memlimit", "bigmemtest", "bigaddrspacetest", + "BasicTestRunner", "run_unittest", "run_doctest", "threading_setup", + "threading_cleanup", "reap_children", "cpython_only", "check_impl_detail", + "get_attribute", "swap_item", "swap_attr", "requires_IEEE_754", "TestHandler", "Matcher", "can_symlink", "skip_unless_symlink"] @@ -381,6 +380,21 @@ port = sock.getsockname()[1] return port +def _is_ipv6_enabled(): + """Check whether IPv6 is enabled on this host.""" + if socket.has_ipv6: + try: + sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) + sock.bind(('::1', 0)) + except (socket.error, socket.gaierror): + pass + else: + sock.close() + return True + return False + +IPV6_ENABLED = _is_ipv6_enabled() + # decorator for skipping tests on non-IEEE 754 platforms requires_IEEE_754 = unittest.skipUnless( float.__getformat__("double").startswith("IEEE"), diff --git a/Lib/test/test_ftplib.py b/Lib/test/test_ftplib.py --- a/Lib/test/test_ftplib.py +++ b/Lib/test/test_ftplib.py @@ -873,7 +873,7 @@ def test_main(): tests = [TestFTPClass, TestTimeouts] - if socket.has_ipv6: + if support.IPV6_ENABLED: try: DummyFTPServer((HOST, 0), af=socket.AF_INET6) except socket.error: diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -24,18 +24,6 @@ except ImportError: fcntl = False -def try_address(host, port=0, family=socket.AF_INET): - """Try to bind a socket on the given host:port and return True - if that has been possible.""" - try: - sock = socket.socket(family, socket.SOCK_STREAM) - sock.bind((host, port)) - except (socket.error, socket.gaierror): - return False - else: - sock.close() - return True - def linux_version(): try: # platform.release() is something like '2.6.33.7-desktop-2mnb' @@ -46,7 +34,6 @@ HOST = support.HOST MSG = 'Michael Gilfix was here\u1234\r\n'.encode('utf-8') ## test unicode string and carriage return -SUPPORTS_IPV6 = socket.has_ipv6 and try_address('::1', family=socket.AF_INET6) try: import _thread as thread @@ -645,7 +632,7 @@ socket.getaddrinfo('localhost', 80) socket.getaddrinfo('127.0.0.1', 80) socket.getaddrinfo(None, 80) - if SUPPORTS_IPV6: + if support.IPV6_ENABLED: socket.getaddrinfo('::1', 80) # port can be a string service name such as "http", a numeric # port number or None diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -523,6 +523,10 @@ Tests ----- +- Issue #11811: Factor out detection of IPv6 support on the current host + and make it available as ``test.support.IPV6_ENABLED``. Patch by + Charles-Fran?ois Natali. + - Issue #10914: Add a minimal embedding test to test_capi. - Issue #11223: Skip test_lock_acquire_interruption() and -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Apr 28 19:24:54 2011 From: python-checkins at python.org (antoine.pitrou) Date: Thu, 28 Apr 2011 19:24:54 +0200 Subject: [Python-checkins] cpython: Issue #11811: ssl.get_server_certificate() is now IPv6-compatible. Patch Message-ID: http://hg.python.org/cpython/rev/d3166c359714 changeset: 69673:d3166c359714 user: Antoine Pitrou date: Thu Apr 28 19:23:55 2011 +0200 summary: Issue #11811: ssl.get_server_certificate() is now IPv6-compatible. Patch by Charles-Fran?ois Natali. files: Doc/library/ssl.rst | 3 ++ Lib/ssl.py | 6 ++-- Lib/test/test_ssl.py | 41 +++++++++++++++++-------------- Misc/NEWS | 3 ++ 4 files changed, 32 insertions(+), 21 deletions(-) diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst --- a/Doc/library/ssl.rst +++ b/Doc/library/ssl.rst @@ -239,6 +239,9 @@ will attempt to validate the server certificate against that set of root certificates, and will fail if the validation attempt fails. + .. versionchanged:: 3.3 + This function is now IPv6-compatible. + .. function:: DER_cert_to_PEM_cert(DER_cert_bytes) Given a certificate as a DER-encoded blob of bytes, returns a PEM-encoded diff --git a/Lib/ssl.py b/Lib/ssl.py --- a/Lib/ssl.py +++ b/Lib/ssl.py @@ -81,7 +81,7 @@ from socket import getnameinfo as _getnameinfo from socket import error as socket_error -from socket import socket, AF_INET, SOCK_STREAM +from socket import socket, AF_INET, SOCK_STREAM, create_connection import base64 # for DER-to-PEM translation import traceback import errno @@ -543,9 +543,9 @@ cert_reqs = CERT_REQUIRED else: cert_reqs = CERT_NONE - s = wrap_socket(socket(), ssl_version=ssl_version, + s = create_connection(addr) + s = wrap_socket(s, ssl_version=ssl_version, cert_reqs=cert_reqs, ca_certs=ca_certs) - s.connect(addr) dercert = s.getpeercert(True) s.close() return DER_cert_to_PEM_cert(dercert) diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -604,25 +604,30 @@ sys.stdout.write("\nNeeded %d calls to do_handshake() to establish session.\n" % count) def test_get_server_certificate(self): - with support.transient_internet("svn.python.org"): - pem = ssl.get_server_certificate(("svn.python.org", 443)) - if not pem: - self.fail("No server certificate on svn.python.org:443!") + def _test_get_server_certificate(host, port, cert=None): + with support.transient_internet(host): + pem = ssl.get_server_certificate((host, port)) + if not pem: + self.fail("No server certificate on %s:%s!" % (host, port)) + + try: + pem = ssl.get_server_certificate((host, port), ca_certs=CERTFILE) + except ssl.SSLError as x: + #should fail + if support.verbose: + sys.stdout.write("%s\n" % x) + else: + self.fail("Got server certificate %s for %s:%s!" % (pem, host, port)) + + pem = ssl.get_server_certificate((host, port), ca_certs=cert) + if not pem: + self.fail("No server certificate on %s:%s!" % (host, port)) + if support.verbose: + sys.stdout.write("\nVerified certificate for %s:%s is\n%s\n" % (host, port ,pem)) - try: - pem = ssl.get_server_certificate(("svn.python.org", 443), ca_certs=CERTFILE) - except ssl.SSLError as x: - #should fail - if support.verbose: - sys.stdout.write("%s\n" % x) - else: - self.fail("Got server certificate %s for svn.python.org!" % pem) - - pem = ssl.get_server_certificate(("svn.python.org", 443), ca_certs=SVN_PYTHON_ORG_ROOT_CERT) - if not pem: - self.fail("No server certificate on svn.python.org:443!") - if support.verbose: - sys.stdout.write("\nVerified certificate for svn.python.org:443 is\n%s\n" % pem) + _test_get_server_certificate('svn.python.org', 443, SVN_PYTHON_ORG_ROOT_CERT) + if support.IPV6_ENABLED: + _test_get_server_certificate('ipv6.google.com', 443) def test_ciphers(self): remote = ("svn.python.org", 443) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -127,6 +127,9 @@ Library ------- +- Issue #11811: ssl.get_server_certificate() is now IPv6-compatible. Patch + by Charles-Fran?ois Natali. + - Issue #11763: don't use difflib in TestCase.assertMultiLineEqual if the strings are too long. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Apr 28 19:24:54 2011 From: python-checkins at python.org (antoine.pitrou) Date: Thu, 28 Apr 2011 19:24:54 +0200 Subject: [Python-checkins] cpython: Fix whitespace Message-ID: http://hg.python.org/cpython/rev/19ab4d6d313f changeset: 69674:19ab4d6d313f user: Antoine Pitrou date: Thu Apr 28 19:24:46 2011 +0200 summary: Fix whitespace files: Lib/test/test_ssl.py | 10 +++++----- 1 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -609,7 +609,7 @@ pem = ssl.get_server_certificate((host, port)) if not pem: self.fail("No server certificate on %s:%s!" % (host, port)) - + try: pem = ssl.get_server_certificate((host, port), ca_certs=CERTFILE) except ssl.SSLError as x: @@ -617,13 +617,13 @@ if support.verbose: sys.stdout.write("%s\n" % x) else: - self.fail("Got server certificate %s for %s:%s!" % (pem, host, port)) - + self.fail("Got server certificate %s for %s:%s!" % (pem, host, port)) + pem = ssl.get_server_certificate((host, port), ca_certs=cert) if not pem: - self.fail("No server certificate on %s:%s!" % (host, port)) + self.fail("No server certificate on %s:%s!" % (host, port)) if support.verbose: - sys.stdout.write("\nVerified certificate for %s:%s is\n%s\n" % (host, port ,pem)) + sys.stdout.write("\nVerified certificate for %s:%s is\n%s\n" % (host, port ,pem)) _test_get_server_certificate('svn.python.org', 443, SVN_PYTHON_ORG_ROOT_CERT) if support.IPV6_ENABLED: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 29 00:45:26 2011 From: python-checkins at python.org (brian.curtin) Date: Fri, 29 Apr 2011 00:45:26 +0200 Subject: [Python-checkins] cpython: Implement #11832. Add an option to start regrtest and wait for input Message-ID: http://hg.python.org/cpython/rev/3d9800fcce7f changeset: 69675:3d9800fcce7f user: Brian Curtin date: Thu Apr 28 17:45:17 2011 -0500 summary: Implement #11832. Add an option to start regrtest and wait for input before continuing. This is useful for starting up the test suite to attach a debugger such as Visual Studio or others. files: Lib/test/regrtest.py | 5 ++++- 1 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -24,6 +24,7 @@ -- dump the traceback and exit if a test takes more than TIMEOUT seconds (default: 30 minutes); disable the timeout if TIMEOUT is zero +--wait -- wait for user input, e.g., allow a debugger to be attached Verbosity @@ -279,7 +280,7 @@ 'use=', 'threshold=', 'trace', 'coverdir=', 'nocoverdir', 'runleaks', 'huntrleaks=', 'memlimit=', 'randseed=', 'multiprocess=', 'coverage', 'slaveargs=', 'forever', 'debug', - 'start=', 'nowindows', 'header', 'testdir=', 'timeout=']) + 'start=', 'nowindows', 'header', 'testdir=', 'timeout=', 'wait']) except getopt.error as msg: usage(msg) @@ -419,6 +420,8 @@ "faulthandler.dump_tracebacks_later", file=sys.stderr) sys.exit(1) timeout = float(a) + elif o == '--wait': + input("Press any key to continue...") else: print(("No handler for option {}. Please report this as a bug " "at http://bugs.python.org.").format(o), file=sys.stderr) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 29 00:49:49 2011 From: python-checkins at python.org (antoine.pitrou) Date: Fri, 29 Apr 2011 00:49:49 +0200 Subject: [Python-checkins] cpython (3.2): Add WSANO_DATA to possible errors triggered by getaddrinfo (Windows) Message-ID: http://hg.python.org/cpython/rev/89ebde7cd8ea changeset: 69676:89ebde7cd8ea branch: 3.2 parent: 69668:32031e33d793 user: Antoine Pitrou date: Fri Apr 29 00:44:33 2011 +0200 summary: Add WSANO_DATA to possible errors triggered by getaddrinfo (Windows) files: Lib/test/support.py | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/Lib/test/support.py b/Lib/test/support.py --- a/Lib/test/support.py +++ b/Lib/test/support.py @@ -839,6 +839,8 @@ default_gai_errnos = [ ('EAI_NONAME', -2), ('EAI_NODATA', -5), + # Encountered when trying to resolve IPv6-only hostnames + ('WSANO_DATA', 11004), ] denied = ResourceDenied("Resource '%s' is not available" % resource_name) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 29 00:49:50 2011 From: python-checkins at python.org (antoine.pitrou) Date: Fri, 29 Apr 2011 00:49:50 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Add WSANO_DATA to possible errors triggered by getaddrinfo (Windows) Message-ID: http://hg.python.org/cpython/rev/1e3c6fedcf8e changeset: 69677:1e3c6fedcf8e parent: 69674:19ab4d6d313f parent: 69676:89ebde7cd8ea user: Antoine Pitrou date: Fri Apr 29 00:49:03 2011 +0200 summary: Add WSANO_DATA to possible errors triggered by getaddrinfo (Windows) files: Lib/test/support.py | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/Lib/test/support.py b/Lib/test/support.py --- a/Lib/test/support.py +++ b/Lib/test/support.py @@ -835,6 +835,8 @@ default_gai_errnos = [ ('EAI_NONAME', -2), ('EAI_NODATA', -5), + # Encountered when trying to resolve IPv6-only hostnames + ('WSANO_DATA', 11004), ] denied = ResourceDenied("Resource '%s' is not available" % resource_name) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 29 00:49:51 2011 From: python-checkins at python.org (antoine.pitrou) Date: Fri, 29 Apr 2011 00:49:51 +0200 Subject: [Python-checkins] cpython (merge default -> default): Merge Message-ID: http://hg.python.org/cpython/rev/10f547214895 changeset: 69678:10f547214895 parent: 69677:1e3c6fedcf8e parent: 69675:3d9800fcce7f user: Antoine Pitrou date: Fri Apr 29 00:49:33 2011 +0200 summary: Merge files: Lib/test/regrtest.py | 5 ++++- 1 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -24,6 +24,7 @@ -- dump the traceback and exit if a test takes more than TIMEOUT seconds (default: 30 minutes); disable the timeout if TIMEOUT is zero +--wait -- wait for user input, e.g., allow a debugger to be attached Verbosity @@ -279,7 +280,7 @@ 'use=', 'threshold=', 'trace', 'coverdir=', 'nocoverdir', 'runleaks', 'huntrleaks=', 'memlimit=', 'randseed=', 'multiprocess=', 'coverage', 'slaveargs=', 'forever', 'debug', - 'start=', 'nowindows', 'header', 'testdir=', 'timeout=']) + 'start=', 'nowindows', 'header', 'testdir=', 'timeout=', 'wait']) except getopt.error as msg: usage(msg) @@ -419,6 +420,8 @@ "faulthandler.dump_tracebacks_later", file=sys.stderr) sys.exit(1) timeout = float(a) + elif o == '--wait': + input("Press any key to continue...") else: print(("No handler for option {}. Please report this as a bug " "at http://bugs.python.org.").format(o), file=sys.stderr) -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Fri Apr 29 04:59:10 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Fri, 29 Apr 2011 04:59:10 +0200 Subject: [Python-checkins] Daily reference leaks (10f547214895): sum=0 Message-ID: results for 10f547214895 on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogOC3mvD', '-x'] From python-checkins at python.org Fri Apr 29 06:13:22 2011 From: python-checkins at python.org (ezio.melotti) Date: Fri, 29 Apr 2011 06:13:22 +0200 Subject: [Python-checkins] cpython (2.7): #11952: Fix typo in multiprocessing doc. Message-ID: http://hg.python.org/cpython/rev/ef9bccfe64de changeset: 69679:ef9bccfe64de branch: 2.7 parent: 69671:a6b772599594 user: Ezio Melotti date: Fri Apr 29 07:10:24 2011 +0300 summary: #11952: Fix typo in multiprocessing doc. files: Doc/library/multiprocessing.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst --- a/Doc/library/multiprocessing.rst +++ b/Doc/library/multiprocessing.rst @@ -28,7 +28,7 @@ .. note:: - Functionality within this package requires that the ``__main__`` method be + Functionality within this package requires that the ``__main__`` module be importable by the children. This is covered in :ref:`multiprocessing-programming` however it is worth pointing out here. This means that some examples, such as the :class:`multiprocessing.Pool` examples will not work in the -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 29 06:13:25 2011 From: python-checkins at python.org (ezio.melotti) Date: Fri, 29 Apr 2011 06:13:25 +0200 Subject: [Python-checkins] cpython (3.1): #11952: Fix typo in multiprocessing doc. Message-ID: http://hg.python.org/cpython/rev/1d3c5df88589 changeset: 69680:1d3c5df88589 branch: 3.1 parent: 69660:7c307fd57021 user: Ezio Melotti date: Fri Apr 29 07:10:24 2011 +0300 summary: #11952: Fix typo in multiprocessing doc. files: Doc/library/multiprocessing.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst --- a/Doc/library/multiprocessing.rst +++ b/Doc/library/multiprocessing.rst @@ -26,7 +26,7 @@ .. note:: - Functionality within this package requires that the ``__main__`` method be + Functionality within this package requires that the ``__main__`` module be importable by the children. This is covered in :ref:`multiprocessing-programming` however it is worth pointing out here. This means that some examples, such as the :class:`multiprocessing.Pool` examples will not work in the -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 29 06:13:26 2011 From: python-checkins at python.org (ezio.melotti) Date: Fri, 29 Apr 2011 06:13:26 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): #11952: merge with 3.1. Message-ID: http://hg.python.org/cpython/rev/56c187b81d2b changeset: 69681:56c187b81d2b branch: 3.2 parent: 69676:89ebde7cd8ea parent: 69680:1d3c5df88589 user: Ezio Melotti date: Fri Apr 29 07:12:42 2011 +0300 summary: #11952: merge with 3.1. files: Doc/library/multiprocessing.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst --- a/Doc/library/multiprocessing.rst +++ b/Doc/library/multiprocessing.rst @@ -26,7 +26,7 @@ .. note:: - Functionality within this package requires that the ``__main__`` method be + Functionality within this package requires that the ``__main__`` module be importable by the children. This is covered in :ref:`multiprocessing-programming` however it is worth pointing out here. This means that some examples, such as the :class:`multiprocessing.Pool` examples will not work in the -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 29 06:13:28 2011 From: python-checkins at python.org (ezio.melotti) Date: Fri, 29 Apr 2011 06:13:28 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): #11952: merge with 3.2. Message-ID: http://hg.python.org/cpython/rev/8eb794bbb967 changeset: 69682:8eb794bbb967 parent: 69678:10f547214895 parent: 69681:56c187b81d2b user: Ezio Melotti date: Fri Apr 29 07:13:12 2011 +0300 summary: #11952: merge with 3.2. files: Doc/library/multiprocessing.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst --- a/Doc/library/multiprocessing.rst +++ b/Doc/library/multiprocessing.rst @@ -26,7 +26,7 @@ .. note:: - Functionality within this package requires that the ``__main__`` method be + Functionality within this package requires that the ``__main__`` module be importable by the children. This is covered in :ref:`multiprocessing-programming` however it is worth pointing out here. This means that some examples, such as the :class:`multiprocessing.Pool` examples will not work in the -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 29 11:39:22 2011 From: python-checkins at python.org (lukasz.langa) Date: Fri, 29 Apr 2011 11:39:22 +0200 Subject: [Python-checkins] cpython (3.2): TestChainMap was not previously used. Minor corrections applied. Message-ID: http://hg.python.org/cpython/rev/0b21d948eabb changeset: 69683:0b21d948eabb branch: 3.2 parent: 69681:56c187b81d2b user: ?ukasz Langa date: Fri Apr 29 11:35:03 2011 +0200 summary: TestChainMap was not previously used. Minor corrections applied. files: Lib/test/test_collections.py | 16 ++++++++-------- 1 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Lib/test/test_collections.py b/Lib/test/test_collections.py --- a/Lib/test/test_collections.py +++ b/Lib/test/test_collections.py @@ -10,7 +10,7 @@ import keyword import re import sys -from collections import _ChainMap as ChainMap +from collections import _ChainMap from collections import Hashable, Iterable, Iterator from collections import Sized, Container, Callable from collections import Set, MutableSet @@ -26,7 +26,7 @@ class TestChainMap(unittest.TestCase): def test_basics(self): - c = ChainMap() + c = _ChainMap() c['a'] = 1 c['b'] = 2 d = c.new_child() @@ -71,7 +71,7 @@ for m1, m2 in zip(d.maps, e.maps): self.assertIsNot(m1, m2, e) - d.new_child() + d = d.new_child() d['b'] = 5 self.assertEqual(d.maps, [{'b': 5}, {'c':30}, {'a':1, 'b':2}]) self.assertEqual(d.parents.maps, [{'c':30}, {'a':1, 'b':2}]) # check parents @@ -79,11 +79,11 @@ self.assertEqual(d.parents['b'], 2) # look beyond maps[0] def test_contructor(self): - self.assertEqual(ChainedContext().maps, [{}]) # no-args --> one new dict - self.assertEqual(ChainMap({1:2}).maps, [{1:2}]) # 1 arg --> list + self.assertEqual(_ChainMap().maps, [{}]) # no-args --> one new dict + self.assertEqual(_ChainMap({1:2}).maps, [{1:2}]) # 1 arg --> list def test_missing(self): - class DefaultChainMap(ChainMap): + class DefaultChainMap(_ChainMap): def __missing__(self, key): return 999 d = DefaultChainMap(dict(a=1, b=2), dict(b=20, c=30)) @@ -100,7 +100,7 @@ d.popitem() def test_dict_coercion(self): - d = ChainMap(dict(a=1, b=2), dict(b=20, c=30)) + d = _ChainMap(dict(a=1, b=2), dict(b=20, c=30)) self.assertEqual(dict(d), dict(a=1, b=2, c=30)) self.assertEqual(dict(d.items()), dict(a=1, b=2, c=30)) @@ -1190,7 +1190,7 @@ def test_main(verbose=None): NamedTupleDocs = doctest.DocTestSuite(module=collections) test_classes = [TestNamedTuple, NamedTupleDocs, TestOneTrickPonyABCs, - TestCollectionABCs, TestCounter, + TestCollectionABCs, TestCounter, TestChainMap, TestOrderedDict, GeneralMappingTests, SubclassMappingTests] support.run_unittest(*test_classes) support.run_doctest(collections, verbose) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 29 11:39:23 2011 From: python-checkins at python.org (lukasz.langa) Date: Fri, 29 Apr 2011 11:39:23 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Empty merge for TestChainMap tweaks in 3.2 Message-ID: http://hg.python.org/cpython/rev/1768fed3aedb changeset: 69684:1768fed3aedb parent: 69682:8eb794bbb967 parent: 69683:0b21d948eabb user: ?ukasz Langa date: Fri Apr 29 11:38:30 2011 +0200 summary: Empty merge for TestChainMap tweaks in 3.2 files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 29 13:46:02 2011 From: python-checkins at python.org (georg.brandl) Date: Fri, 29 Apr 2011 13:46:02 +0200 Subject: [Python-checkins] cpython: Small grammar fix. Message-ID: http://hg.python.org/cpython/rev/f8bbd0c29e43 changeset: 69685:f8bbd0c29e43 user: Georg Brandl date: Fri Apr 29 13:45:54 2011 +0200 summary: Small grammar fix. files: Doc/whatsnew/3.3.rst | 4 ++-- 1 files changed, 2 insertions(+), 2 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 @@ -136,10 +136,10 @@ * Stub -Unsupported operating systems +Unsupported Operating Systems ============================= -OS/2 and VMS are no more supported because of the lack of maintainer. +OS/2 and VMS are no more supported because of the lack of a maintainer. Porting to Python 3.3 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 29 16:18:10 2011 From: python-checkins at python.org (lukasz.langa) Date: Fri, 29 Apr 2011 16:18:10 +0200 Subject: [Python-checkins] cpython (3.2): __class__ of a __class__ check worked only by chance. Message-ID: http://hg.python.org/cpython/rev/b7309b24528d changeset: 69686:b7309b24528d branch: 3.2 parent: 69683:0b21d948eabb user: ?ukasz Langa date: Fri Apr 29 16:15:41 2011 +0200 summary: __class__ of a __class__ check worked only by chance. files: Lib/test/test_cfgparser.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_cfgparser.py b/Lib/test/test_cfgparser.py --- a/Lib/test/test_cfgparser.py +++ b/Lib/test/test_cfgparser.py @@ -993,7 +993,7 @@ cf.add_section(123) cf.set(123, 'this is sick', True) self.assertEqual(cf.get(123, 'this is sick'), True) - if cf._dict.__class__ is configparser._default_dict: + if cf._dict is configparser._default_dict: # would not work for SortedDict; only checking for the most common # default dictionary (OrderedDict) cf.optionxform = lambda x: x -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 29 16:18:11 2011 From: python-checkins at python.org (lukasz.langa) Date: Fri, 29 Apr 2011 16:18:11 +0200 Subject: [Python-checkins] cpython (3.2): Removed debugging leftovers. Message-ID: http://hg.python.org/cpython/rev/546cae2917ec changeset: 69687:546cae2917ec branch: 3.2 user: ?ukasz Langa date: Fri Apr 29 16:16:36 2011 +0200 summary: Removed debugging leftovers. files: Lib/configparser.py | 2 -- 1 files changed, 0 insertions(+), 2 deletions(-) diff --git a/Lib/configparser.py b/Lib/configparser.py --- a/Lib/configparser.py +++ b/Lib/configparser.py @@ -1057,8 +1057,6 @@ if not optname: e = self._handle_error(e, fpname, lineno, line) optname = self.optionxform(optname.rstrip()) - if hasattr(self, '__ping__'): - import pdb; pdb.set_trace() if (self._strict and (sectname, optname) in elements_added): raise DuplicateOptionError(sectname, optname, -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 29 16:18:12 2011 From: python-checkins at python.org (lukasz.langa) Date: Fri, 29 Apr 2011 16:18:12 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merged minor cleanups from 3.2. Message-ID: http://hg.python.org/cpython/rev/b41eef4b1804 changeset: 69688:b41eef4b1804 parent: 69685:f8bbd0c29e43 parent: 69687:546cae2917ec user: ?ukasz Langa date: Fri Apr 29 16:17:51 2011 +0200 summary: Merged minor cleanups from 3.2. files: Lib/configparser.py | 2 -- Lib/test/test_configparser.py | 2 +- 2 files changed, 1 insertions(+), 3 deletions(-) diff --git a/Lib/configparser.py b/Lib/configparser.py --- a/Lib/configparser.py +++ b/Lib/configparser.py @@ -1058,8 +1058,6 @@ if not optname: e = self._handle_error(e, fpname, lineno, line) optname = self.optionxform(optname.rstrip()) - if hasattr(self, '__ping__'): - import pdb; pdb.set_trace() if (self._strict and (sectname, optname) in elements_added): raise DuplicateOptionError(sectname, optname, diff --git a/Lib/test/test_configparser.py b/Lib/test/test_configparser.py --- a/Lib/test/test_configparser.py +++ b/Lib/test/test_configparser.py @@ -993,7 +993,7 @@ cf.add_section(123) cf.set(123, 'this is sick', True) self.assertEqual(cf.get(123, 'this is sick'), True) - if cf._dict.__class__ is configparser._default_dict: + if cf._dict is configparser._default_dict: # would not work for SortedDict; only checking for the most common # default dictionary (OrderedDict) cf.optionxform = lambda x: x -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 29 23:29:16 2011 From: python-checkins at python.org (brian.curtin) Date: Fri, 29 Apr 2011 23:29:16 +0200 Subject: [Python-checkins] cpython (3.1): Further fix #7838. CREATE_NEW_CONSOLE was exposed, but none of the Message-ID: http://hg.python.org/cpython/rev/80971f71b0d9 changeset: 69689:80971f71b0d9 branch: 3.1 parent: 69680:1d3c5df88589 user: Brian Curtin date: Fri Apr 29 15:48:13 2011 -0500 summary: Further fix #7838. CREATE_NEW_CONSOLE was exposed, but none of the constants to be used for STARTUPINFO were exposed due to the change. files: Lib/subprocess.py | 11 +++++++++-- 1 files changed, 9 insertions(+), 2 deletions(-) diff --git a/Lib/subprocess.py b/Lib/subprocess.py --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -344,7 +344,6 @@ if mswindows: - from _subprocess import CREATE_NEW_CONSOLE import threading import msvcrt import _subprocess @@ -372,7 +371,15 @@ "getoutput", "check_output", "CalledProcessError"] if mswindows: - __all__.append("CREATE_NEW_CONSOLE") + from _subprocess import (CREATE_NEW_CONSOLE, + STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, + STD_ERROR_HANDLE, SW_HIDE, + STARTF_USESTDHANDLES, STARTF_USESHOWWINDOW) + + __all__.extend(["CREATE_NEW_CONSOLE", + "STD_INPUT_HANDLE", "STD_OUTPUT_HANDLE", + "STD_ERROR_HANDLE", "SW_HIDE", + "STARTF_USESTDHANDLES", "STARTF_USESHOWWINDOW"]) try: MAXFD = os.sysconf("SC_OPEN_MAX") except: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 29 23:29:17 2011 From: python-checkins at python.org (brian.curtin) Date: Fri, 29 Apr 2011 23:29:17 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): merge Message-ID: http://hg.python.org/cpython/rev/4c3ae7d04664 changeset: 69690:4c3ae7d04664 branch: 3.2 parent: 69687:546cae2917ec parent: 69689:80971f71b0d9 user: Brian Curtin date: Fri Apr 29 16:11:30 2011 -0500 summary: merge files: Lib/subprocess.py | 11 +++++++++-- 1 files changed, 9 insertions(+), 2 deletions(-) diff --git a/Lib/subprocess.py b/Lib/subprocess.py --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -415,8 +415,15 @@ "getoutput", "check_output", "CalledProcessError"] if mswindows: - from _subprocess import CREATE_NEW_CONSOLE, CREATE_NEW_PROCESS_GROUP - __all__.extend(["CREATE_NEW_CONSOLE", "CREATE_NEW_PROCESS_GROUP"]) + from _subprocess import (CREATE_NEW_CONSOLE, CREATE_NEW_PROCESS_GROUP, + STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, + STD_ERROR_HANDLE, SW_HIDE, + STARTF_USESTDHANDLES, STARTF_USESHOWWINDOW) + + __all__.extend(["CREATE_NEW_CONSOLE", "CREATE_NEW_PROCESS_GROUP", + "STD_INPUT_HANDLE", "STD_OUTPUT_HANDLE", + "STD_ERROR_HANDLE", "SW_HIDE", + "STARTF_USESTDHANDLES", "STARTF_USESHOWWINDOW"]) try: MAXFD = os.sysconf("SC_OPEN_MAX") except: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 29 23:29:18 2011 From: python-checkins at python.org (brian.curtin) Date: Fri, 29 Apr 2011 23:29:18 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): merge Message-ID: http://hg.python.org/cpython/rev/c73875eaa9ac changeset: 69691:c73875eaa9ac parent: 69688:b41eef4b1804 parent: 69690:4c3ae7d04664 user: Brian Curtin date: Fri Apr 29 16:14:55 2011 -0500 summary: merge files: Lib/subprocess.py | 11 +++++++++-- 1 files changed, 9 insertions(+), 2 deletions(-) diff --git a/Lib/subprocess.py b/Lib/subprocess.py --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -435,8 +435,15 @@ "getoutput", "check_output", "CalledProcessError", "DEVNULL"] if mswindows: - from _subprocess import CREATE_NEW_CONSOLE, CREATE_NEW_PROCESS_GROUP - __all__.extend(["CREATE_NEW_CONSOLE", "CREATE_NEW_PROCESS_GROUP"]) + from _subprocess import (CREATE_NEW_CONSOLE, CREATE_NEW_PROCESS_GROUP, + STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, + STD_ERROR_HANDLE, SW_HIDE, + STARTF_USESTDHANDLES, STARTF_USESHOWWINDOW) + + __all__.extend(["CREATE_NEW_CONSOLE", "CREATE_NEW_PROCESS_GROUP", + "STD_INPUT_HANDLE", "STD_OUTPUT_HANDLE", + "STD_ERROR_HANDLE", "SW_HIDE", + "STARTF_USESTDHANDLES", "STARTF_USESHOWWINDOW"]) try: MAXFD = os.sysconf("SC_OPEN_MAX") except: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 29 23:29:24 2011 From: python-checkins at python.org (brian.curtin) Date: Fri, 29 Apr 2011 23:29:24 +0200 Subject: [Python-checkins] cpython (2.7): merge Message-ID: http://hg.python.org/cpython/rev/768d58f7357c changeset: 69692:768d58f7357c branch: 2.7 parent: 69679:ef9bccfe64de user: Brian Curtin date: Fri Apr 29 16:21:51 2011 -0500 summary: merge files: Lib/subprocess.py | 11 +++++++++-- 1 files changed, 9 insertions(+), 2 deletions(-) diff --git a/Lib/subprocess.py b/Lib/subprocess.py --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -441,8 +441,15 @@ "check_output", "CalledProcessError"] if mswindows: - from _subprocess import CREATE_NEW_CONSOLE, CREATE_NEW_PROCESS_GROUP - __all__.extend(["CREATE_NEW_CONSOLE", "CREATE_NEW_PROCESS_GROUP"]) + from _subprocess import (CREATE_NEW_CONSOLE, CREATE_NEW_PROCESS_GROUP, + STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, + STD_ERROR_HANDLE, SW_HIDE, + STARTF_USESTDHANDLES, STARTF_USESHOWWINDOW) + + __all__.extend(["CREATE_NEW_CONSOLE", "CREATE_NEW_PROCESS_GROUP", + "STD_INPUT_HANDLE", "STD_OUTPUT_HANDLE", + "STD_ERROR_HANDLE", "SW_HIDE", + "STARTF_USESTDHANDLES", "STARTF_USESHOWWINDOW"]) try: MAXFD = os.sysconf("SC_OPEN_MAX") except: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 29 23:29:25 2011 From: python-checkins at python.org (brian.curtin) Date: Fri, 29 Apr 2011 23:29:25 +0200 Subject: [Python-checkins] cpython: whitespace fix Message-ID: http://hg.python.org/cpython/rev/4e3ff53b6f59 changeset: 69693:4e3ff53b6f59 parent: 69691:c73875eaa9ac user: Brian Curtin date: Fri Apr 29 16:24:07 2011 -0500 summary: whitespace fix files: Lib/subprocess.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/subprocess.py b/Lib/subprocess.py --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -439,7 +439,7 @@ STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, STD_ERROR_HANDLE, SW_HIDE, STARTF_USESTDHANDLES, STARTF_USESHOWWINDOW) - + __all__.extend(["CREATE_NEW_CONSOLE", "CREATE_NEW_PROCESS_GROUP", "STD_INPUT_HANDLE", "STD_OUTPUT_HANDLE", "STD_ERROR_HANDLE", "SW_HIDE", -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Apr 29 23:29:26 2011 From: python-checkins at python.org (brian.curtin) Date: Fri, 29 Apr 2011 23:29:26 +0200 Subject: [Python-checkins] cpython (2.7): whitespace fix Message-ID: http://hg.python.org/cpython/rev/d5936bfa28d3 changeset: 69694:d5936bfa28d3 branch: 2.7 parent: 69692:768d58f7357c user: Brian Curtin date: Fri Apr 29 16:28:52 2011 -0500 summary: whitespace fix files: Lib/subprocess.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/subprocess.py b/Lib/subprocess.py --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -445,7 +445,7 @@ STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, STD_ERROR_HANDLE, SW_HIDE, STARTF_USESTDHANDLES, STARTF_USESHOWWINDOW) - + __all__.extend(["CREATE_NEW_CONSOLE", "CREATE_NEW_PROCESS_GROUP", "STD_INPUT_HANDLE", "STD_OUTPUT_HANDLE", "STD_ERROR_HANDLE", "SW_HIDE", -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 30 00:12:39 2011 From: python-checkins at python.org (senthil.kumaran) Date: Sat, 30 Apr 2011 00:12:39 +0200 Subject: [Python-checkins] cpython (3.1): Wrap the testskip decorator for the proper test to resolve bb failure. Message-ID: http://hg.python.org/cpython/rev/c4a9149d467f changeset: 69695:c4a9149d467f branch: 3.1 parent: 69689:80971f71b0d9 user: Senthil Kumaran date: Sat Apr 30 06:06:28 2011 +0800 summary: Wrap the testskip decorator for the proper test to resolve bb failure. files: Lib/test/test_tarfile.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py --- a/Lib/test/test_tarfile.py +++ b/Lib/test/test_tarfile.py @@ -249,7 +249,6 @@ data = open(os.path.join(TEMPDIR, "ustar/symtype"), "rb").read() self.assertEqual(md5sum(data), md5_regtype) - @unittest.skipUnless(hasattr(os,'symlink'), "needs os.symlink") def test_extractall(self): # Test if extractall() correctly restores directory permissions # and times (see issue1735). @@ -679,6 +678,7 @@ finally: shutil.rmtree(tempdir) + @unittest.skipUnless(hasattr(os,'symlink'), "needs os.symlink") def test_extractall_symlinks(self): # Test if extractall works properly when tarfile contains symlinks tempdir = os.path.join(TEMPDIR, "testsymlinks") -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 30 00:12:41 2011 From: python-checkins at python.org (senthil.kumaran) Date: Sat, 30 Apr 2011 00:12:41 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): merge from 3.1 Message-ID: http://hg.python.org/cpython/rev/fc5db1cd4ebf changeset: 69696:fc5db1cd4ebf branch: 3.2 parent: 69690:4c3ae7d04664 parent: 69695:c4a9149d467f user: Senthil Kumaran date: Sat Apr 30 06:09:51 2011 +0800 summary: merge from 3.1 files: Lib/test/test_tarfile.py | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py --- a/Lib/test/test_tarfile.py +++ b/Lib/test/test_tarfile.py @@ -351,7 +351,6 @@ finally: tar.close() - @support.skip_unless_symlink def test_extractall(self): # Test if extractall() correctly restores directory permissions # and times (see issue1735). @@ -983,6 +982,8 @@ self.assertEqual(t.name, cmp_path or path.replace(os.sep, "/")) + + @support.skip_unless_symlink def test_extractall_symlinks(self): # Test if extractall works properly when tarfile contains symlinks tempdir = os.path.join(TEMPDIR, "testsymlinks") -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 30 00:12:43 2011 From: python-checkins at python.org (senthil.kumaran) Date: Sat, 30 Apr 2011 00:12:43 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Wrap the correct test with the skip decorator for the issue10761. Message-ID: http://hg.python.org/cpython/rev/2665a28643b8 changeset: 69697:2665a28643b8 parent: 69693:4e3ff53b6f59 parent: 69696:fc5db1cd4ebf user: Senthil Kumaran date: Sat Apr 30 06:12:25 2011 +0800 summary: Wrap the correct test with the skip decorator for the issue10761. merge from 3.2. files: Lib/test/test_tarfile.py | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py --- a/Lib/test/test_tarfile.py +++ b/Lib/test/test_tarfile.py @@ -351,7 +351,6 @@ finally: tar.close() - @support.skip_unless_symlink def test_extractall(self): # Test if extractall() correctly restores directory permissions # and times (see issue1735). @@ -983,6 +982,8 @@ self.assertEqual(t.name, cmp_path or path.replace(os.sep, "/")) + + @support.skip_unless_symlink def test_extractall_symlinks(self): # Test if extractall works properly when tarfile contains symlinks tempdir = os.path.join(TEMPDIR, "testsymlinks") -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Sat Apr 30 05:00:50 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sat, 30 Apr 2011 05:00:50 +0200 Subject: [Python-checkins] Daily reference leaks (2665a28643b8): sum=0 Message-ID: results for 2665a28643b8 on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflog6462ek', '-x'] From python-checkins at python.org Sat Apr 30 05:24:36 2011 From: python-checkins at python.org (brian.curtin) Date: Sat, 30 Apr 2011 05:24:36 +0200 Subject: [Python-checkins] cpython (3.1): Fix #11961. Document STARTUPINFO and creation flag options. Message-ID: http://hg.python.org/cpython/rev/609ca9d71aba changeset: 69698:609ca9d71aba branch: 3.1 parent: 69695:c4a9149d467f user: Brian Curtin date: Fri Apr 29 22:17:51 2011 -0500 summary: Fix #11961. Document STARTUPINFO and creation flag options. files: Doc/library/subprocess.rst | 101 ++++++++++++++++++++++++- 1 files changed, 98 insertions(+), 3 deletions(-) diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst --- a/Doc/library/subprocess.rst +++ b/Doc/library/subprocess.rst @@ -171,9 +171,9 @@ :attr:`stdout`, :attr:`stdin` and :attr:`stderr` are not updated by the :meth:`communicate` method. - The *startupinfo* and *creationflags*, if given, will be passed to the - underlying CreateProcess() function. They can specify things such as appearance - of the main window and priority for the new process. (Windows only) + If given, *startupinfo* will be a :class:`STARTUPINFO` object, which is + passed to the underlying ``CreateProcess`` function. + *creationflags*, if given, can be :data:`CREATE_NEW_CONSOLE`. (Windows only) .. data:: PIPE @@ -428,6 +428,101 @@ ``N`` (Unix only). +Windows Popen Helpers +--------------------- + +The :class:`STARTUPINFO` class and following constants are only available +on Windows. + +.. class:: STARTUPINFO() + + Partial support of the Windows + `STARTUPINFO `__ + structure is used for :class:`Popen` creation. + + .. attribute:: dwFlags + + A bit field that determines whether certain :class:`STARTUPINFO` members + are used when the process creates a window. :: + + si = subprocess.STARTUPINFO() + si.dwFlags = subprocess.STARTF_USESTDHANDLES | subprocess.STARTF_USESHOWWINDOW + + .. attribute:: hStdInput + + If :attr:`dwFlags` specifies :data:`STARTF_USESTDHANDLES`, this member is + the standard input handle for the process. If :data:`STARTF_USESTDHANDLES` + is not specified, the default for standard input is the keyboard buffer. + + .. attribute:: hStdOutput + + If :attr:`dwFlags` specifies :data:`STARTF_USESTDHANDLES`, this member is + the standard output handle for the process. Otherwise, this member is + ignored and the default for standard output is the console window's + buffer. + + .. attribute:: hStdError + + If :attr:`dwFlags` specifies :data:`STARTF_USESTDHANDLES`, this member is + the standard error handle for the process. Otherwise, this member is + ignored and the default for standard error is the console window's buffer. + + .. attribute:: wShowWindow + + If :attr:`dwFlags` specifies :data:`STARTF_USESHOWWINDOW`, this member + can be any of the values that can be specified in the ``nCmdShow`` + parameter for the + `ShowWindow `__ + function, except for ``SW_SHOWDEFAULT``. Otherwise, this member is + ignored. + + :data:`SW_HIDE` is provided for this attribute. It is used when + :class:`Popen` is called with ``shell=True``. + + +Constants +^^^^^^^^^ + +The :mod:`subprocess` module exposes the following constants. + +.. data:: STD_INPUT_HANDLE + + The standard input device. Initially, this is the console input buffer, + ``CONIN$``. + +.. data:: STD_OUTPUT_HANDLE + + The standard output device. Initially, this is the active console screen + buffer, ``CONOUT$``. + +.. data:: STD_ERROR_HANDLE + + The standard error device. Initially, this is the active console screen + buffer, ``CONOUT$``. + +.. data:: SW_HIDE + + Hides the window. Another window will be activated. + +.. data:: STARTF_USESTDHANDLES + + Specifies that the :attr:`STARTUPINFO.hStdInput`, + :attr:`STARTUPINFO.hStdOutput`, and :attr:`STARTUPINFO.hStdError` members + contain additional information. + +.. data:: STARTF_USESHOWWINDOW + + Specifies that the :attr:`STARTUPINFO.wShowWindow` member contains + additional information. + +.. data:: CREATE_NEW_CONSOLE + + The new process has a new console, instead of inheriting its parent's + console (the default). + + This flag is always set when :class:`Popen` is created with ``shell=True``. + + .. _subprocess-replacements: Replacing Older Functions with the subprocess Module -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 30 05:24:37 2011 From: python-checkins at python.org (brian.curtin) Date: Sat, 30 Apr 2011 05:24:37 +0200 Subject: [Python-checkins] cpython (3.1): whitespace... Message-ID: http://hg.python.org/cpython/rev/cd68b3031f00 changeset: 69699:cd68b3031f00 branch: 3.1 user: Brian Curtin date: Fri Apr 29 22:18:33 2011 -0500 summary: whitespace... files: Doc/library/subprocess.rst | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst --- a/Doc/library/subprocess.rst +++ b/Doc/library/subprocess.rst @@ -435,7 +435,7 @@ on Windows. .. class:: STARTUPINFO() - + Partial support of the Windows `STARTUPINFO `__ structure is used for :class:`Popen` creation. @@ -475,7 +475,7 @@ `ShowWindow `__ function, except for ``SW_SHOWDEFAULT``. Otherwise, this member is ignored. - + :data:`SW_HIDE` is provided for this attribute. It is used when :class:`Popen` is called with ``shell=True``. @@ -519,7 +519,7 @@ The new process has a new console, instead of inheriting its parent's console (the default). - + This flag is always set when :class:`Popen` is created with ``shell=True``. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 30 05:24:42 2011 From: python-checkins at python.org (brian.curtin) Date: Sat, 30 Apr 2011 05:24:42 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): Fix #11961. Document STARTUPINFO and creation flag options. Message-ID: http://hg.python.org/cpython/rev/f0092c611004 changeset: 69700:f0092c611004 branch: 3.2 parent: 69696:fc5db1cd4ebf parent: 69699:cd68b3031f00 user: Brian Curtin date: Fri Apr 29 22:20:57 2011 -0500 summary: Fix #11961. Document STARTUPINFO and creation flag options. files: Doc/library/subprocess.rst | 110 ++++++++++++++++++++++++- 1 files changed, 107 insertions(+), 3 deletions(-) diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst --- a/Doc/library/subprocess.rst +++ b/Doc/library/subprocess.rst @@ -212,9 +212,10 @@ :attr:`stdout`, :attr:`stdin` and :attr:`stderr` are not updated by the :meth:`communicate` method. - The *startupinfo* and *creationflags*, if given, will be passed to the - underlying CreateProcess() function. They can specify things such as appearance - of the main window and priority for the new process. (Windows only) + If given, *startupinfo* will be a :class:`STARTUPINFO` object, which is + passed to the underlying ``CreateProcess`` function. + *creationflags*, if given, can be :data:`CREATE_NEW_CONSOLE` or + :data:`CREATE_NEW_PROCESS_GROUP`. (Windows only) Popen objects are supported as context managers via the :keyword:`with` statement, closing any open file descriptors on exit. @@ -482,6 +483,109 @@ ``N`` (Unix only). +Windows Popen Helpers +--------------------- + +The :class:`STARTUPINFO` class and following constants are only available +on Windows. + +.. class:: STARTUPINFO() + + Partial support of the Windows + `STARTUPINFO `__ + structure is used for :class:`Popen` creation. + + .. attribute:: dwFlags + + A bit field that determines whether certain :class:`STARTUPINFO` members + are used when the process creates a window. :: + + si = subprocess.STARTUPINFO() + si.dwFlags = subprocess.STARTF_USESTDHANDLES | subprocess.STARTF_USESHOWWINDOW + + .. attribute:: hStdInput + + If :attr:`dwFlags` specifies :data:`STARTF_USESTDHANDLES`, this member is + the standard input handle for the process. If :data:`STARTF_USESTDHANDLES` + is not specified, the default for standard input is the keyboard buffer. + + .. attribute:: hStdOutput + + If :attr:`dwFlags` specifies :data:`STARTF_USESTDHANDLES`, this member is + the standard output handle for the process. Otherwise, this member is + ignored and the default for standard output is the console window's + buffer. + + .. attribute:: hStdError + + If :attr:`dwFlags` specifies :data:`STARTF_USESTDHANDLES`, this member is + the standard error handle for the process. Otherwise, this member is + ignored and the default for standard error is the console window's buffer. + + .. attribute:: wShowWindow + + If :attr:`dwFlags` specifies :data:`STARTF_USESHOWWINDOW`, this member + can be any of the values that can be specified in the ``nCmdShow`` + parameter for the + `ShowWindow `__ + function, except for ``SW_SHOWDEFAULT``. Otherwise, this member is + ignored. + + :data:`SW_HIDE` is provided for this attribute. It is used when + :class:`Popen` is called with ``shell=True``. + + +Constants +^^^^^^^^^ + +The :mod:`subprocess` module exposes the following constants. + +.. data:: STD_INPUT_HANDLE + + The standard input device. Initially, this is the console input buffer, + ``CONIN$``. + +.. data:: STD_OUTPUT_HANDLE + + The standard output device. Initially, this is the active console screen + buffer, ``CONOUT$``. + +.. data:: STD_ERROR_HANDLE + + The standard error device. Initially, this is the active console screen + buffer, ``CONOUT$``. + +.. data:: SW_HIDE + + Hides the window. Another window will be activated. + +.. data:: STARTF_USESTDHANDLES + + Specifies that the :attr:`STARTUPINFO.hStdInput`, + :attr:`STARTUPINFO.hStdOutput`, and :attr:`STARTUPINFO.hStdError` members + contain additional information. + +.. data:: STARTF_USESHOWWINDOW + + Specifies that the :attr:`STARTUPINFO.wShowWindow` member contains + additional information. + +.. data:: CREATE_NEW_CONSOLE + + The new process has a new console, instead of inheriting its parent's + console (the default). + + This flag is always set when :class:`Popen` is created with ``shell=True``. + +.. data:: CREATE_NEW_PROCESS_GROUP + + A :class:`Popen` ``creationflags`` parameter to specify that a new process + group will be created. This flag is necessary for using :func:`os.kill` + on the subprocess. + + This flag is ignored if :data:`CREATE_NEW_CONSOLE` is specified. + + .. _subprocess-replacements: Replacing Older Functions with the subprocess Module -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 30 05:24:43 2011 From: python-checkins at python.org (brian.curtin) Date: Sat, 30 Apr 2011 05:24:43 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Fix #11961. Document STARTUPINFO and creation flag options. Message-ID: http://hg.python.org/cpython/rev/f8fae22a1ff0 changeset: 69701:f8fae22a1ff0 parent: 69697:2665a28643b8 parent: 69700:f0092c611004 user: Brian Curtin date: Fri Apr 29 22:21:35 2011 -0500 summary: Fix #11961. Document STARTUPINFO and creation flag options. files: Doc/library/subprocess.rst | 110 ++++++++++++++++++++++++- 1 files changed, 107 insertions(+), 3 deletions(-) diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst --- a/Doc/library/subprocess.rst +++ b/Doc/library/subprocess.rst @@ -214,9 +214,10 @@ :attr:`stdout`, :attr:`stdin` and :attr:`stderr` are not updated by the :meth:`communicate` method. - The *startupinfo* and *creationflags*, if given, will be passed to the - underlying CreateProcess() function. They can specify things such as appearance - of the main window and priority for the new process. (Windows only) + If given, *startupinfo* will be a :class:`STARTUPINFO` object, which is + passed to the underlying ``CreateProcess`` function. + *creationflags*, if given, can be :data:`CREATE_NEW_CONSOLE` or + :data:`CREATE_NEW_PROCESS_GROUP`. (Windows only) Popen objects are supported as context managers via the :keyword:`with` statement, closing any open file descriptors on exit. @@ -551,6 +552,109 @@ ``N`` (Unix only). +Windows Popen Helpers +--------------------- + +The :class:`STARTUPINFO` class and following constants are only available +on Windows. + +.. class:: STARTUPINFO() + + Partial support of the Windows + `STARTUPINFO `__ + structure is used for :class:`Popen` creation. + + .. attribute:: dwFlags + + A bit field that determines whether certain :class:`STARTUPINFO` members + are used when the process creates a window. :: + + si = subprocess.STARTUPINFO() + si.dwFlags = subprocess.STARTF_USESTDHANDLES | subprocess.STARTF_USESHOWWINDOW + + .. attribute:: hStdInput + + If :attr:`dwFlags` specifies :data:`STARTF_USESTDHANDLES`, this member is + the standard input handle for the process. If :data:`STARTF_USESTDHANDLES` + is not specified, the default for standard input is the keyboard buffer. + + .. attribute:: hStdOutput + + If :attr:`dwFlags` specifies :data:`STARTF_USESTDHANDLES`, this member is + the standard output handle for the process. Otherwise, this member is + ignored and the default for standard output is the console window's + buffer. + + .. attribute:: hStdError + + If :attr:`dwFlags` specifies :data:`STARTF_USESTDHANDLES`, this member is + the standard error handle for the process. Otherwise, this member is + ignored and the default for standard error is the console window's buffer. + + .. attribute:: wShowWindow + + If :attr:`dwFlags` specifies :data:`STARTF_USESHOWWINDOW`, this member + can be any of the values that can be specified in the ``nCmdShow`` + parameter for the + `ShowWindow `__ + function, except for ``SW_SHOWDEFAULT``. Otherwise, this member is + ignored. + + :data:`SW_HIDE` is provided for this attribute. It is used when + :class:`Popen` is called with ``shell=True``. + + +Constants +^^^^^^^^^ + +The :mod:`subprocess` module exposes the following constants. + +.. data:: STD_INPUT_HANDLE + + The standard input device. Initially, this is the console input buffer, + ``CONIN$``. + +.. data:: STD_OUTPUT_HANDLE + + The standard output device. Initially, this is the active console screen + buffer, ``CONOUT$``. + +.. data:: STD_ERROR_HANDLE + + The standard error device. Initially, this is the active console screen + buffer, ``CONOUT$``. + +.. data:: SW_HIDE + + Hides the window. Another window will be activated. + +.. data:: STARTF_USESTDHANDLES + + Specifies that the :attr:`STARTUPINFO.hStdInput`, + :attr:`STARTUPINFO.hStdOutput`, and :attr:`STARTUPINFO.hStdError` members + contain additional information. + +.. data:: STARTF_USESHOWWINDOW + + Specifies that the :attr:`STARTUPINFO.wShowWindow` member contains + additional information. + +.. data:: CREATE_NEW_CONSOLE + + The new process has a new console, instead of inheriting its parent's + console (the default). + + This flag is always set when :class:`Popen` is created with ``shell=True``. + +.. data:: CREATE_NEW_PROCESS_GROUP + + A :class:`Popen` ``creationflags`` parameter to specify that a new process + group will be created. This flag is necessary for using :func:`os.kill` + on the subprocess. + + This flag is ignored if :data:`CREATE_NEW_CONSOLE` is specified. + + .. _subprocess-replacements: Replacing Older Functions with the subprocess Module -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 30 05:24:45 2011 From: python-checkins at python.org (brian.curtin) Date: Sat, 30 Apr 2011 05:24:45 +0200 Subject: [Python-checkins] cpython (2.7): Fix #11961. Document STARTUPINFO and creation flag options. Message-ID: http://hg.python.org/cpython/rev/9a31422649f1 changeset: 69702:9a31422649f1 branch: 2.7 parent: 69694:d5936bfa28d3 user: Brian Curtin date: Fri Apr 29 22:23:46 2011 -0500 summary: Fix #11961. Document STARTUPINFO and creation flag options. files: Doc/library/subprocess.rst | 110 ++++++++++++++++++++++++- 1 files changed, 107 insertions(+), 3 deletions(-) diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst --- a/Doc/library/subprocess.rst +++ b/Doc/library/subprocess.rst @@ -178,9 +178,10 @@ :attr:`stdout`, :attr:`stdin` and :attr:`stderr` are not updated by the communicate() method. - The *startupinfo* and *creationflags*, if given, will be passed to the - underlying CreateProcess() function. They can specify things such as appearance - of the main window and priority for the new process. (Windows only) + If given, *startupinfo* will be a :class:`STARTUPINFO` object, which is + passed to the underlying ``CreateProcess`` function. + *creationflags*, if given, can be :data:`CREATE_NEW_CONSOLE` or + :data:`CREATE_NEW_PROCESS_GROUP`. (Windows only) .. data:: PIPE @@ -413,6 +414,109 @@ ``N`` (Unix only). +Windows Popen Helpers +--------------------- + +The :class:`STARTUPINFO` class and following constants are only available +on Windows. + +.. class:: STARTUPINFO() + + Partial support of the Windows + `STARTUPINFO `__ + structure is used for :class:`Popen` creation. + + .. attribute:: dwFlags + + A bit field that determines whether certain :class:`STARTUPINFO` members + are used when the process creates a window. :: + + si = subprocess.STARTUPINFO() + si.dwFlags = subprocess.STARTF_USESTDHANDLES | subprocess.STARTF_USESHOWWINDOW + + .. attribute:: hStdInput + + If :attr:`dwFlags` specifies :data:`STARTF_USESTDHANDLES`, this member is + the standard input handle for the process. If :data:`STARTF_USESTDHANDLES` + is not specified, the default for standard input is the keyboard buffer. + + .. attribute:: hStdOutput + + If :attr:`dwFlags` specifies :data:`STARTF_USESTDHANDLES`, this member is + the standard output handle for the process. Otherwise, this member is + ignored and the default for standard output is the console window's + buffer. + + .. attribute:: hStdError + + If :attr:`dwFlags` specifies :data:`STARTF_USESTDHANDLES`, this member is + the standard error handle for the process. Otherwise, this member is + ignored and the default for standard error is the console window's buffer. + + .. attribute:: wShowWindow + + If :attr:`dwFlags` specifies :data:`STARTF_USESHOWWINDOW`, this member + can be any of the values that can be specified in the ``nCmdShow`` + parameter for the + `ShowWindow `__ + function, except for ``SW_SHOWDEFAULT``. Otherwise, this member is + ignored. + + :data:`SW_HIDE` is provided for this attribute. It is used when + :class:`Popen` is called with ``shell=True``. + + +Constants +^^^^^^^^^ + +The :mod:`subprocess` module exposes the following constants. + +.. data:: STD_INPUT_HANDLE + + The standard input device. Initially, this is the console input buffer, + ``CONIN$``. + +.. data:: STD_OUTPUT_HANDLE + + The standard output device. Initially, this is the active console screen + buffer, ``CONOUT$``. + +.. data:: STD_ERROR_HANDLE + + The standard error device. Initially, this is the active console screen + buffer, ``CONOUT$``. + +.. data:: SW_HIDE + + Hides the window. Another window will be activated. + +.. data:: STARTF_USESTDHANDLES + + Specifies that the :attr:`STARTUPINFO.hStdInput`, + :attr:`STARTUPINFO.hStdOutput`, and :attr:`STARTUPINFO.hStdError` members + contain additional information. + +.. data:: STARTF_USESHOWWINDOW + + Specifies that the :attr:`STARTUPINFO.wShowWindow` member contains + additional information. + +.. data:: CREATE_NEW_CONSOLE + + The new process has a new console, instead of inheriting its parent's + console (the default). + + This flag is always set when :class:`Popen` is created with ``shell=True``. + +.. data:: CREATE_NEW_PROCESS_GROUP + + A :class:`Popen` ``creationflags`` parameter to specify that a new process + group will be created. This flag is necessary for using :func:`os.kill` + on the subprocess. + + This flag is ignored if :data:`CREATE_NEW_CONSOLE` is specified. + + .. _subprocess-replacements: Replacing Older Functions with the subprocess Module -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 30 07:53:11 2011 From: python-checkins at python.org (eli.bendersky) Date: Sat, 30 Apr 2011 07:53:11 +0200 Subject: [Python-checkins] cpython (2.7): Issue #10912: add clarification for PyObject_RichCompareBool comparing Message-ID: http://hg.python.org/cpython/rev/d27f95e3b52f changeset: 69703:d27f95e3b52f branch: 2.7 user: Eli Bendersky date: Sat Apr 30 08:51:55 2011 +0300 summary: Issue #10912: add clarification for PyObject_RichCompareBool comparing identical objects files: Doc/c-api/object.rst | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/Doc/c-api/object.rst b/Doc/c-api/object.rst --- a/Doc/c-api/object.rst +++ b/Doc/c-api/object.rst @@ -108,6 +108,9 @@ Python expression ``o1 op o2``, where ``op`` is the operator corresponding to *opid*. +.. note:: + If *o1* and *o2* are the same object, :c:func:`PyObject_RichCompareBool` + will always return ``1`` for :const:`Py_EQ` and ``0`` for :const:`Py_NE`. .. cfunction:: int PyObject_Cmp(PyObject *o1, PyObject *o2, int *result) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 30 08:02:13 2011 From: python-checkins at python.org (eli.bendersky) Date: Sat, 30 Apr 2011 08:02:13 +0200 Subject: [Python-checkins] cpython (2.7): fix formatting, :c:func: --> :cfunc: Message-ID: http://hg.python.org/cpython/rev/1a45c92f9716 changeset: 69704:1a45c92f9716 branch: 2.7 user: Eli Bendersky date: Sat Apr 30 09:02:12 2011 +0300 summary: fix formatting, :c:func: --> :cfunc: files: Doc/c-api/object.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/c-api/object.rst b/Doc/c-api/object.rst --- a/Doc/c-api/object.rst +++ b/Doc/c-api/object.rst @@ -109,7 +109,7 @@ *opid*. .. note:: - If *o1* and *o2* are the same object, :c:func:`PyObject_RichCompareBool` + If *o1* and *o2* are the same object, :cfunc:`PyObject_RichCompareBool` will always return ``1`` for :const:`Py_EQ` and ``0`` for :const:`Py_NE`. .. cfunction:: int PyObject_Cmp(PyObject *o1, PyObject *o2, int *result) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 30 09:47:29 2011 From: python-checkins at python.org (lukasz.langa) Date: Sat, 30 Apr 2011 09:47:29 +0200 Subject: [Python-checkins] cpython (3.2): Mentioned issues #11324 and #11858. Message-ID: http://hg.python.org/cpython/rev/08996a664ed3 changeset: 69705:08996a664ed3 branch: 3.2 parent: 69700:f0092c611004 user: ?ukasz Langa date: Sat Apr 30 09:36:35 2011 +0200 summary: Mentioned issues #11324 and #11858. files: Misc/NEWS | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -70,6 +70,11 @@ Library ------- +- Issue #11858: configparser.ExtendedInterpolation expected lower-case section + names. + +- Issue #11324: ConfigParser(interpolation=None) now works correctly. + - Issue #11763: don't use difflib in TestCase.assertMultiLineEqual if the strings are too long. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 30 09:47:41 2011 From: python-checkins at python.org (lukasz.langa) Date: Sat, 30 Apr 2011 09:47:41 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merged mentions of issues #11324 and #11858. Message-ID: http://hg.python.org/cpython/rev/0c21de0cca44 changeset: 69706:0c21de0cca44 parent: 69701:f8fae22a1ff0 parent: 69705:08996a664ed3 user: ?ukasz Langa date: Sat Apr 30 09:47:21 2011 +0200 summary: Merged mentions of issues #11324 and #11858. Possibly redundant once 3.2.1 is out. files: Misc/NEWS | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -127,6 +127,11 @@ Library ------- +- Issue #11858: configparser.ExtendedInterpolation expected lower-case section + names. + +- Issue #11324: ConfigParser(interpolation=None) now works correctly. + - Issue #11811: ssl.get_server_certificate() is now IPv6-compatible. Patch by Charles-Fran?ois Natali. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 30 14:17:47 2011 From: python-checkins at python.org (victor.stinner) Date: Sat, 30 Apr 2011 14:17:47 +0200 Subject: [Python-checkins] cpython (3.2): Issue #10914: Py_NewInterpreter() uses PyErr_PrintEx(0) Message-ID: http://hg.python.org/cpython/rev/5a983773c09a changeset: 69707:5a983773c09a branch: 3.2 parent: 69705:08996a664ed3 user: Victor Stinner date: Wed Apr 27 00:20:27 2011 +0200 summary: Issue #10914: Py_NewInterpreter() uses PyErr_PrintEx(0) ... instead of PyErr_Print() because we don't need to set sys attributes, the sys module is destroyed just after printing the error. files: Python/pythonrun.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Python/pythonrun.c b/Python/pythonrun.c --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -622,7 +622,7 @@ handle_error: /* Oops, it didn't work. Undo it all. */ - PyErr_Print(); + PyErr_PrintEx(0); PyThreadState_Clear(tstate); PyThreadState_Swap(save_tstate); PyThreadState_Delete(tstate); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 30 14:17:48 2011 From: python-checkins at python.org (victor.stinner) Date: Sat, 30 Apr 2011 14:17:48 +0200 Subject: [Python-checkins] cpython (3.2): Issue #10914: Initialize correctly the filesystem codec when creating a new Message-ID: http://hg.python.org/cpython/rev/2caf82aee7a4 changeset: 69708:2caf82aee7a4 branch: 3.2 user: Victor Stinner date: Wed Apr 27 00:24:21 2011 +0200 summary: Issue #10914: Initialize correctly the filesystem codec when creating a new subinterpreter to fix a bootstrap issue with codecs implemented in Python, as the ISO-8859-15 codec. Add fscodec_initialized attribute to the PyInterpreterState structure. files: Include/pystate.h | 1 + Misc/NEWS | 4 ++++ Objects/unicodeobject.c | 29 ++++++++++++++++++++++------- Python/pystate.c | 1 + Python/pythonrun.c | 23 +++++++++++++++-------- 5 files changed, 43 insertions(+), 15 deletions(-) diff --git a/Include/pystate.h b/Include/pystate.h --- a/Include/pystate.h +++ b/Include/pystate.h @@ -31,6 +31,7 @@ PyObject *codec_search_cache; PyObject *codec_error_registry; int codecs_initialized; + int fscodec_initialized; #ifdef HAVE_DLOPEN int dlopenflags; diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,10 @@ Core and Builtins ----------------- +- Issue #10914: Initialize correctly the filesystem codec when creating a new + subinterpreter to fix a bootstrap issue with codecs implemented in Python, as + the ISO-8859-15 codec. + - Issue #10517: After fork(), reinitialize the TLS used by the PyGILState_* APIs, to avoid a crash with the pthread implementation in RHEL 5. Patch by Charles-Fran?ois Natali. diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -1626,7 +1626,17 @@ PyUnicode_GET_SIZE(unicode), "surrogateescape"); #else - if (Py_FileSystemDefaultEncoding) { + PyInterpreterState *interp = PyThreadState_GET()->interp; + /* Bootstrap check: if the filesystem codec is implemented in Python, we + cannot use it to encode and decode filenames before it is loaded. Load + the Python codec requires to encode at least its own filename. Use the C + version of the locale codec until the codec registry is initialized and + the Python codec is loaded. + + Py_FileSystemDefaultEncoding is shared between all interpreters, we + cannot only rely on it: check also interp->fscodec_initialized for + subinterpreters. */ + if (Py_FileSystemDefaultEncoding && interp->fscodec_initialized) { return PyUnicode_AsEncodedString(unicode, Py_FileSystemDefaultEncoding, "surrogateescape"); @@ -1818,12 +1828,17 @@ #elif defined(__APPLE__) return PyUnicode_DecodeUTF8(s, size, "surrogateescape"); #else - /* During the early bootstrapping process, Py_FileSystemDefaultEncoding - can be undefined. If it is case, decode using UTF-8. The following assumes - that Py_FileSystemDefaultEncoding is set to a built-in encoding during the - bootstrapping process where the codecs aren't ready yet. - */ - if (Py_FileSystemDefaultEncoding) { + PyInterpreterState *interp = PyThreadState_GET()->interp; + /* Bootstrap check: if the filesystem codec is implemented in Python, we + cannot use it to encode and decode filenames before it is loaded. Load + the Python codec requires to encode at least its own filename. Use the C + version of the locale codec until the codec registry is initialized and + the Python codec is loaded. + + Py_FileSystemDefaultEncoding is shared between all interpreters, we + cannot only rely on it: check also interp->fscodec_initialized for + subinterpreters. */ + if (Py_FileSystemDefaultEncoding && interp->fscodec_initialized) { return PyUnicode_Decode(s, size, Py_FileSystemDefaultEncoding, "surrogateescape"); diff --git a/Python/pystate.c b/Python/pystate.c --- a/Python/pystate.c +++ b/Python/pystate.c @@ -79,6 +79,7 @@ interp->codec_search_cache = NULL; interp->codec_error_registry = NULL; interp->codecs_initialized = 0; + interp->fscodec_initialized = 0; #ifdef HAVE_DLOPEN #ifdef RTLD_NOW interp->dlopenflags = RTLD_NOW; diff --git a/Python/pythonrun.c b/Python/pythonrun.c --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -53,7 +53,7 @@ /* Forward */ static void initmain(void); -static void initfsencoding(void); +static int initfsencoding(PyInterpreterState *interp); static void initsite(void); static int initstdio(void); static void flush_io(void); @@ -291,7 +291,8 @@ _PyTime_Init(); - initfsencoding(); + if (initfsencoding(interp) < 0) + Py_FatalError("Py_Initialize: unable to load the file system codec"); if (install_sigs) initsigs(); /* Signal handling stuff, including initintr() */ @@ -608,6 +609,10 @@ Py_DECREF(pstderr); _PyImportHooks_Init(); + + if (initfsencoding(interp) < 0) + goto handle_error; + if (initstdio() < 0) Py_FatalError( "Py_Initialize: can't initialize sys standard streams"); @@ -720,8 +725,8 @@ } } -static void -initfsencoding(void) +static int +initfsencoding(PyInterpreterState *interp) { PyObject *codec; #if defined(HAVE_LANGINFO_H) && defined(CODESET) @@ -738,7 +743,8 @@ Py_FileSystemDefaultEncoding = codeset; Py_HasFileSystemDefaultEncoding = 0; - return; + interp->fscodec_initialized = 1; + return 0; } #endif @@ -748,10 +754,11 @@ /* Such error can only occurs in critical situations: no more * memory, import a module of the standard library failed, * etc. */ - Py_FatalError("Py_Initialize: unable to load the file system codec"); - } else { - Py_DECREF(codec); + return -1; } + Py_DECREF(codec); + interp->fscodec_initialized = 1; + return 0; } /* Import the site module (not into __main__ though) */ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 30 14:19:59 2011 From: python-checkins at python.org (victor.stinner) Date: Sat, 30 Apr 2011 14:19:59 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge 3.2: ignore commits (already done in 3.3 previously) Message-ID: http://hg.python.org/cpython/rev/ce859b848879 changeset: 69709:ce859b848879 parent: 69706:0c21de0cca44 parent: 69708:2caf82aee7a4 user: Victor Stinner date: Sat Apr 30 14:19:57 2011 +0200 summary: Merge 3.2: ignore commits (already done in 3.3 previously) files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 30 15:01:52 2011 From: python-checkins at python.org (victor.stinner) Date: Sat, 30 Apr 2011 15:01:52 +0200 Subject: [Python-checkins] cpython: Issue #11223: Replace threading._info() by sys.thread_info Message-ID: http://hg.python.org/cpython/rev/2b21fcf3d9a9 changeset: 69710:2b21fcf3d9a9 user: Victor Stinner date: Sat Apr 30 14:53:09 2011 +0200 summary: Issue #11223: Replace threading._info() by sys.thread_info files: Doc/library/sys.rst | 29 +++++++ Doc/library/threading.rst | 24 ------ Doc/whatsnew/3.3.rst | 7 +- Include/pythread.h | 2 +- Lib/_dummy_thread.py | 3 - Lib/test/test_os.py | 13 +-- Lib/test/test_sys.py | 8 ++ Lib/test/test_threading.py | 12 +-- Lib/test/test_threadsignals.py | 5 +- Lib/threading.py | 3 +- Modules/_threadmodule.c | 13 --- Python/sysmodule.c | 24 +++-- Python/thread.c | 83 ++++++++++++++------- 13 files changed, 119 insertions(+), 107 deletions(-) diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -961,6 +961,35 @@ to a console and Python apps started with :program:`pythonw`. +.. data:: thread_info + + A :term:`struct sequence` holding information about the thread + implementation. + + +------------------+---------------------------------------------------------+ + | Attribute | Explanation | + +==================+=========================================================+ + | :const:`name` | Name of the thread implementation: | + | | | + | | * ``'nt'``: Windows threads | + | | * ``'os2'``: OS/2 threads | + | | * ``'pthread'``: POSIX threads | + | | * ``'solaris'``: Solaris threads | + +------------------+---------------------------------------------------------+ + | :const:`lock` | Name of the lock implementation: | + | | | + | | * ``'semaphore'``: a lock uses a semaphore | + | | * ``'mutex+cond'``: a lock uses a mutex | + | | and a condition variable | + | | * ``None`` if this information is unknown | + +------------------+---------------------------------------------------------+ + | :const:`version` | Name and version of the thread library. It is a string, | + | | or ``None`` if these informations are unknown. | + +------------------+---------------------------------------------------------+ + + .. versionadded:: 3.3 + + .. data:: tracebacklimit When this variable is set to an integer value, it determines the maximum number diff --git a/Doc/library/threading.rst b/Doc/library/threading.rst --- a/Doc/library/threading.rst +++ b/Doc/library/threading.rst @@ -175,30 +175,6 @@ Availability: Windows, systems with POSIX threads. -.. function:: _info() - - Return a dictionary with informations about the thread implementation. - The ``'name'`` key gives the name of the thread implementation (string): - - * ``'nt'``: Windows threads - * ``'os2'``: OS/2 threads - * ``'pthread'``: POSIX threads - * ``'solaris'``: Solaris threads - - POSIX threads have two more keys: - - * ``'lock_implementation'`` (string): name of the lock - implementation - - * ``'semaphore'``: a lock uses a semaphore - * ``'mutex+cond'``: a lock uses a mutex and a condition variable - - * ``'pthread_version'`` (string, optional): name and version of the pthread - library - - .. versionadded:: 3.3 - - This module also defines the following constant: .. data:: TIMEOUT_MAX 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 @@ -112,11 +112,11 @@ (Contributed by Giampaolo Rodol? in :issue:`9795`) -threading ---------- +sys +--- -* The :mod:`threading` module has a new :func:`~threading._info` function which - provides informations about the thread implementation. +* The :mod:`sys` module has a new :func:`~sys.thread_info` :term:`struct + sequence` holding informations about the thread implementation. (:issue:`11223`) diff --git a/Include/pythread.h b/Include/pythread.h --- a/Include/pythread.h +++ b/Include/pythread.h @@ -74,7 +74,7 @@ PyAPI_FUNC(size_t) PyThread_get_stacksize(void); PyAPI_FUNC(int) PyThread_set_stacksize(size_t); -PyAPI_FUNC(PyObject*) _PyThread_Info(void); +PyAPI_FUNC(PyObject*) PyThread_GetInfo(void); /* Thread Local Storage (TLS) API */ PyAPI_FUNC(int) PyThread_create_key(void); diff --git a/Lib/_dummy_thread.py b/Lib/_dummy_thread.py --- a/Lib/_dummy_thread.py +++ b/Lib/_dummy_thread.py @@ -149,6 +149,3 @@ else: global _interrupt _interrupt = True - -def info(): - return {'name': 'dummy'} 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 @@ -27,15 +27,10 @@ # and unmaintained) linuxthreads threading library. There's an issue # when combining linuxthreads with a failed execv call: see # http://bugs.python.org/issue4970. -USING_LINUXTHREADS = False -if threading: - info = threading._info() - try: - pthread_version = info['pthread_version'] - except KeyError: - pass - else: - USING_LINUXTHREADS = pthread_version.startswith("linuxthreads") +if hasattr(sys, 'thread_info') and sys.thread_info.version: + USING_LINUXTHREADS = sys.thread_info.version.startswith("linuxthreads") +else: + USING_LINUXTHREADS = False # Tests creating TESTFN class FileTests(unittest.TestCase): 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 @@ -474,6 +474,14 @@ if not sys.platform.startswith('win'): self.assertIsInstance(sys.abiflags, str) + @unittest.skipUnless(hasattr(sys, 'thread_info'), + 'Threading required for this test.') + def test_thread_info(self): + info = sys.thread_info + self.assertTrue(len(info), 3) + self.assertIn(info.name, ('nt', 'os2', 'pthread', 'solaris', None)) + self.assertIn(info.lock, ('semaphore', 'mutex+cond', None)) + def test_43581(self): # Can't use sys.stdout, as this is a StringIO object when # the test runs under regrtest. diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py --- a/Lib/test/test_threading.py +++ b/Lib/test/test_threading.py @@ -719,16 +719,6 @@ barriertype = staticmethod(threading.Barrier) -class MiscTests(unittest.TestCase): - def test_info(self): - info = threading._info() - self.assertIn(info['name'], - 'nt os2 pthread solaris'.split()) - if info['name'] == 'pthread': - self.assertIn(info['lock_implementation'], - ('semaphore', 'mutex+cond')) - - def test_main(): test.support.run_unittest(LockTests, PyRLockTests, CRLockTests, EventTests, ConditionAsRLockTests, ConditionTests, @@ -736,7 +726,7 @@ ThreadTests, ThreadJoinOnShutdown, ThreadingExceptionTests, - BarrierTests, MiscTests, + BarrierTests, ) if __name__ == "__main__": diff --git a/Lib/test/test_threadsignals.py b/Lib/test/test_threadsignals.py --- a/Lib/test/test_threadsignals.py +++ b/Lib/test/test_threadsignals.py @@ -14,9 +14,8 @@ process_pid = os.getpid() signalled_all=thread.allocate_lock() -info = thread.info() -USING_PTHREAD_COND = (info['name'] == 'pthread' - and info['lock_implementation'] == 'mutex+cond') +USING_PTHREAD_COND = (sys.thread_info.name == 'pthread' + and sys.thread_info.lock == 'mutex+cond') def registerSignals(for_usr1, for_usr2, for_alrm): usr1 = signal.signal(signal.SIGUSR1, for_usr1) diff --git a/Lib/threading.py b/Lib/threading.py --- a/Lib/threading.py +++ b/Lib/threading.py @@ -19,7 +19,7 @@ __all__ = ['active_count', 'Condition', 'current_thread', 'enumerate', 'Event', 'Lock', 'RLock', 'Semaphore', 'BoundedSemaphore', 'Thread', 'Barrier', - 'Timer', 'setprofile', 'settrace', 'local', 'stack_size', '_info'] + 'Timer', 'setprofile', 'settrace', 'local', 'stack_size'] # Rename some stuff so "from threading import *" is safe _start_new_thread = _thread.start_new_thread @@ -31,7 +31,6 @@ except AttributeError: _CRLock = None TIMEOUT_MAX = _thread.TIMEOUT_MAX -_info = _thread.info del _thread diff --git a/Modules/_threadmodule.c b/Modules/_threadmodule.c --- a/Modules/_threadmodule.c +++ b/Modules/_threadmodule.c @@ -1227,17 +1227,6 @@ (4kB pages are common; using multiples of 4096 for the stack size is\n\ the suggested approach in the absence of more specific information)."); -static PyObject * -thread_info(PyObject *self) -{ - return _PyThread_Info(); -} - -PyDoc_STRVAR(thread_info_doc, -"info() -> dict\n\ -\n\ -Informations about the thread implementation."); - static PyMethodDef thread_methods[] = { {"start_new_thread", (PyCFunction)thread_PyThread_start_new_thread, METH_VARARGS, start_new_doc}, @@ -1259,8 +1248,6 @@ METH_NOARGS, _count_doc}, {"stack_size", (PyCFunction)thread_stack_size, METH_VARARGS, stack_size_doc}, - {"info", (PyCFunction)thread_info, - METH_NOARGS, thread_info_doc}, {NULL, NULL} /* sentinel */ }; diff --git a/Python/sysmodule.c b/Python/sysmodule.c --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -17,6 +17,7 @@ #include "Python.h" #include "code.h" #include "frameobject.h" +#include "pythread.h" #include "osdefs.h" @@ -1251,20 +1252,21 @@ "\n\ Static objects:\n\ \n\ -float_info -- a dict with information about the float implementation.\n\ +builtin_module_names -- tuple of module names built into this interpreter\n\ +copyright -- copyright notice pertaining to this interpreter\n\ +exec_prefix -- prefix used to find the machine-specific Python library\n\ +executable -- pathname of this Python interpreter\n\ +float_info -- a struct sequence with information about the float implementation.\n\ +float_repr_style -- string indicating the style of repr() output for floats\n\ +hexversion -- version information encoded as a single integer\n\ int_info -- a struct sequence with information about the int implementation.\n\ maxsize -- the largest supported length of containers.\n\ maxunicode -- the largest supported character\n\ -builtin_module_names -- tuple of module names built into this interpreter\n\ +platform -- platform identifier\n\ +prefix -- prefix used to find the Python library\n\ +thread_info -- a struct sequence with information about the thread implementation.\n\ version -- the version of this interpreter as a string\n\ version_info -- version information as a named tuple\n\ -hexversion -- version information encoded as a single integer\n\ -copyright -- copyright notice pertaining to this interpreter\n\ -platform -- platform identifier\n\ -executable -- pathname of this Python interpreter\n\ -prefix -- prefix used to find the Python library\n\ -exec_prefix -- prefix used to find the machine-specific Python library\n\ -float_repr_style -- string indicating the style of repr() output for floats\n\ " ) #ifdef MS_WINDOWS @@ -1611,6 +1613,10 @@ PyUnicode_FromString("legacy")); #endif +#ifdef WITH_THREAD + SET_SYS_FROM_STRING("thread_info", PyThread_GetInfo()); +#endif + #undef SET_SYS_FROM_STRING if (PyErr_Occurred()) return NULL; diff --git a/Python/thread.c b/Python/thread.c --- a/Python/thread.c +++ b/Python/thread.c @@ -7,7 +7,6 @@ #include "Python.h" - #ifndef _POSIX_THREADS /* This means pthreads are not implemented in libc headers, hence the macro not present in unistd.h. But they still can be implemented as an external @@ -415,26 +414,51 @@ #endif /* Py_HAVE_NATIVE_TLS */ +PyDoc_STRVAR(threadinfo__doc__, +"sys.thread_info\n\ +\n\ +A struct sequence holding information about the thread implementation."); + +static PyStructSequence_Field threadinfo_fields[] = { + {"name", "name of the thread implementation"}, + {"lock", "name of the lock implementation"}, + {"version", "name and version of the thread library"}, + {0} +}; + +static PyStructSequence_Desc threadinfo_desc = { + "sys.thread_info", /* name */ + threadinfo__doc__, /* doc */ + threadinfo_fields, /* fields */ + 3 +}; + +static PyTypeObject ThreadInfoType; + PyObject* -_PyThread_Info(void) +PyThread_GetInfo(void) { - PyObject *info, *value; - int ret; + PyObject *threadinfo, *value; + int pos = 0; #if (defined(_POSIX_THREADS) && defined(HAVE_CONFSTR) \ && defined(_CS_GNU_LIBPTHREAD_VERSION)) char buffer[255]; int len; #endif - info = PyDict_New(); - if (info == NULL) + if (ThreadInfoType.tp_name == 0) + PyStructSequence_InitType(&ThreadInfoType, &threadinfo_desc); + + threadinfo = PyStructSequence_New(&ThreadInfoType); + if (threadinfo == NULL) return NULL; value = PyUnicode_FromString(PYTHREAD_NAME); - ret = PyDict_SetItemString(info, "name", value); - Py_DECREF(value); - if (ret) - goto error; + if (value == NULL) { + Py_DECREF(threadinfo); + return NULL; + } + PyStructSequence_SET_ITEM(threadinfo, pos++, value); #ifdef _POSIX_THREADS #ifdef USE_SEMAPHORES @@ -442,30 +466,31 @@ #else value = PyUnicode_FromString("mutex+cond"); #endif - if (value == NULL) + if (value == NULL) { + Py_DECREF(threadinfo); return NULL; - ret = PyDict_SetItemString(info, "lock_implementation", value); - Py_DECREF(value); - if (ret) - goto error; + } +#else + Py_INCREF(Py_None); + value = Py_None; +#endif + PyStructSequence_SET_ITEM(threadinfo, pos++, value); -#if defined(HAVE_CONFSTR) && defined(_CS_GNU_LIBPTHREAD_VERSION) +#if (defined(_POSIX_THREADS) && defined(HAVE_CONFSTR) \ + && defined(_CS_GNU_LIBPTHREAD_VERSION)) + value = NULL; len = confstr(_CS_GNU_LIBPTHREAD_VERSION, buffer, sizeof(buffer)); - if (0 < len && len < sizeof(buffer)) { + if (1 < len && len < sizeof(buffer)) { value = PyUnicode_DecodeFSDefaultAndSize(buffer, len-1); if (value == NULL) - goto error; - ret = PyDict_SetItemString(info, "pthread_version", value); - Py_DECREF(value); - if (ret) - goto error; + PyErr_Clear(); } + if (value == NULL) #endif -#endif - - return info; - -error: - Py_DECREF(info); - return NULL; + { + Py_INCREF(Py_None); + value = Py_None; + } + PyStructSequence_SET_ITEM(threadinfo, pos++, value); + return threadinfo; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 30 15:22:07 2011 From: python-checkins at python.org (victor.stinner) Date: Sat, 30 Apr 2011 15:22:07 +0200 Subject: [Python-checkins] cpython: Issue #8407, issue #11859: Add signal.pthread_sigmask() function to fetch Message-ID: http://hg.python.org/cpython/rev/28b9702a83d1 changeset: 69711:28b9702a83d1 user: Victor Stinner date: Sat Apr 30 15:21:58 2011 +0200 summary: Issue #8407, issue #11859: Add signal.pthread_sigmask() function to fetch and/or change the signal mask of the calling thread. Fix also tests of test_io using threads and an alarm: use pthread_sigmask() to ensure that the SIGALRM signal is received by the main thread. Original patch written by Jean-Paul Calderone. files: Doc/library/signal.rst | 53 ++++++++++- Doc/whatsnew/3.3.rst | 11 ++- Lib/test/test_io.py | 2 + Lib/test/test_signal.py | 56 +++++++++++- Misc/NEWS | 7 + Modules/signalmodule.c | 139 +++++++++++++++++++++++++++- 6 files changed, 262 insertions(+), 6 deletions(-) diff --git a/Doc/library/signal.rst b/Doc/library/signal.rst --- a/Doc/library/signal.rst +++ b/Doc/library/signal.rst @@ -13,9 +13,6 @@ underlying implementation), with the exception of the handler for :const:`SIGCHLD`, which follows the underlying implementation. -* There is no way to "block" signals temporarily from critical sections (since - this is not supported by all Unix flavors). - * Although Python signal handlers are called asynchronously as far as the Python user is concerned, they can only occur between the "atomic" instructions of the Python interpreter. This means that signals arriving during long calculations @@ -119,6 +116,28 @@ in user and kernel space. SIGPROF is delivered upon expiration. +.. data:: SIG_BLOCK + + A possible value for the *how* parameter to :func:`pthread_sigmask` + indicating that signals are to be blocked. + + .. versionadded:: 3.3 + +.. data:: SIG_UNBLOCK + + A possible value for the *how* parameter to :func:`pthread_sigmask` + indicating that signals are to be unblocked. + + .. versionadded:: 3.3 + +.. data:: SIG_SETMASK + + A possible value for the *how* parameter to :func:`pthread_sigmask` + indicating that the signal mask is to be replaced. + + .. versionadded:: 3.3 + + The :mod:`signal` module defines one exception: .. exception:: ItimerError @@ -161,6 +180,34 @@ :manpage:`signal(2)`.) +.. function:: pthread_sigmask(how, mask) + + Fetch and/or change the signal mask of the calling thread. The signal mask + is the set of signals whose delivery is currently blocked for the caller. + The old signal mask is returned. + + The behavior of the call is dependent on the value of *how*, as follows. + + * :data:`SIG_BLOCK`: The set of blocked signals is the union of the current + set and the *mask* argument. + * :data:`SIG_UNBLOCK`: The signals in *mask* are removed from the current + set of blocked signals. It is permissible to attempt to unblock a + signal which is not blocked. + * :data:`SIG_SETMASK`: The set of blocked signals is set to the *mask* + argument. + + *mask* is a list of signal numbers (e.g. [:const:`signal.SIGINT`, + :const:`signal.SIGTERM`]). + + For example, ``signal.pthread_sigmask(signal.SIG_BLOCK, [])`` reads the + signal mask of the calling thread. + + Availability: Unix. See the man page :manpage:`sigprocmask(3)` and + :manpage:`pthread_sigmask(3)` for further information. + + .. versionadded:: 3.3 + + .. function:: setitimer(which, seconds[, interval]) Sets given interval timer (one of :const:`signal.ITIMER_REAL`, 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 @@ -118,7 +118,16 @@ * The :mod:`sys` module has a new :func:`~sys.thread_info` :term:`struct sequence` holding informations about the thread implementation. - (:issue:`11223`) +(:issue:`11223`) + +signal +------ + +* The :mod:`signal` module has a new :func:`~signal.pthread_sigmask` function + to fetch and/or change the signal mask of the calling thread. + +(Contributed by Jean-Paul Calderone in :issue:`8407`) + Optimizations ============= diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py --- a/Lib/test/test_io.py +++ b/Lib/test/test_io.py @@ -2627,6 +2627,8 @@ in the latter.""" read_results = [] def _read(): + if hasattr(signal, 'pthread_sigmask'): + signal.pthread_sigmask(signal.SIG_BLOCK, [signal.SIGALRM]) s = os.read(r, 1) read_results.append(s) t = threading.Thread(target=_read) diff --git a/Lib/test/test_signal.py b/Lib/test/test_signal.py --- a/Lib/test/test_signal.py +++ b/Lib/test/test_signal.py @@ -483,11 +483,65 @@ # and the handler should have been called self.assertEqual(self.hndl_called, True) + + at unittest.skipUnless(hasattr(signal, 'pthread_sigmask'), + 'need signal.pthread_sigmask()') +class PthreadSigmaskTests(unittest.TestCase): + def test_arguments(self): + self.assertRaises(TypeError, signal.pthread_sigmask) + self.assertRaises(TypeError, signal.pthread_sigmask, 1) + self.assertRaises(TypeError, signal.pthread_sigmask, 1, 2, 3) + self.assertRaises(RuntimeError, signal.pthread_sigmask, 1700, []) + + def test_block_unlock(self): + pid = os.getpid() + signum = signal.SIGUSR1 + + def handler(signum, frame): + handler.tripped = True + handler.tripped = False + + def read_sigmask(): + return signal.pthread_sigmask(signal.SIG_BLOCK, []) + + old_handler = signal.signal(signum, handler) + self.addCleanup(signal.signal, signum, old_handler) + + # unblock SIGUSR1, copy the old mask and test our signal handler + old_mask = signal.pthread_sigmask(signal.SIG_UNBLOCK, [signum]) + self.addCleanup(signal.pthread_sigmask, signal.SIG_SETMASK, old_mask) + os.kill(pid, signum) + self.assertTrue(handler.tripped) + + # block SIGUSR1 + handler.tripped = False + signal.pthread_sigmask(signal.SIG_BLOCK, [signum]) + os.kill(pid, signum) + self.assertFalse(handler.tripped) + + # check the mask + blocked = read_sigmask() + self.assertIn(signum, blocked) + self.assertEqual(set(old_mask) ^ set(blocked), {signum}) + + # unblock SIGUSR1 + signal.pthread_sigmask(signal.SIG_UNBLOCK, [signum]) + os.kill(pid, signum) + self.assertTrue(handler.tripped) + + # check the mask + unblocked = read_sigmask() + self.assertNotIn(signum, unblocked) + self.assertEqual(set(blocked) ^ set(unblocked), {signum}) + self.assertSequenceEqual(old_mask, unblocked) + + def test_main(): try: support.run_unittest(BasicSignalTests, InterProcessSignalTests, WakeupSignalTests, SiginterruptTest, - ItimerTest, WindowsSignalTests) + ItimerTest, WindowsSignalTests, + PthreadSigmaskTests) finally: support.reap_children() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -127,6 +127,9 @@ Library ------- +- Issue #8407: Add signal.pthread_sigmask() function to fetch and/or change the + signal mask of the calling thread. + - Issue #11858: configparser.ExtendedInterpolation expected lower-case section names. @@ -531,6 +534,10 @@ Tests ----- +- Issue #8407, #11859: Fix tests of test_io using threads and an alarm: use + pthread_sigmask() to ensure that the SIGALRM signal is received by the main + thread. + - Issue #11811: Factor out detection of IPv6 support on the current host and make it available as ``test.support.IPV6_ENABLED``. Patch by Charles-Fran?ois Natali. diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c --- a/Modules/signalmodule.c +++ b/Modules/signalmodule.c @@ -22,6 +22,14 @@ #include #endif +#if defined(HAVE_PTHREAD_SIGMASK) && !defined(HAVE_BROKEN_PTHREAD_SIGMASK) +# define PYPTHREAD_SIGMASK +#endif + +#if defined(PYPTHREAD_SIGMASK) && defined(HAVE_PTHREAD_H) +# include +#endif + #ifndef SIG_ERR #define SIG_ERR ((PyOS_sighandler_t)(-1)) #endif @@ -495,6 +503,110 @@ Returns current value of given itimer."); #endif +#ifdef PYPTHREAD_SIGMASK +/* Convert an iterable to a sigset. + Return 0 on success, return -1 and raise an exception on error. */ + +static int +iterable_to_sigset(PyObject *iterable, sigset_t *mask) +{ + int result = -1; + PyObject *iterator, *item; + long signum; + int err; + + sigemptyset(mask); + + iterator = PyObject_GetIter(iterable); + if (iterator == NULL) + goto error; + + while (1) + { + item = PyIter_Next(iterator); + if (item == NULL) { + if (PyErr_Occurred()) + goto error; + else + break; + } + + signum = PyLong_AsLong(item); + Py_DECREF(item); + if (signum == -1 && PyErr_Occurred()) + goto error; + if (0 < signum && signum < NSIG) + err = sigaddset(mask, (int)signum); + else + err = 1; + if (err) { + PyErr_Format(PyExc_ValueError, + "signal number %ld out of range", signum); + goto error; + } + } + result = 0; + +error: + Py_XDECREF(iterator); + return result; +} + +static PyObject * +signal_pthread_sigmask(PyObject *self, PyObject *args) +{ + int how, sig; + PyObject *signals, *result, *signum; + sigset_t mask, previous; + int err; + + if (!PyArg_ParseTuple(args, "iO:pthread_sigmask", &how, &signals)) + return NULL; + + if (iterable_to_sigset(signals, &mask)) + return NULL; + + err = pthread_sigmask(how, &mask, &previous); + if (err != 0) { + errno = err; + PyErr_SetFromErrno(PyExc_RuntimeError); + return NULL; + } + + result = PyList_New(0); + if (result == NULL) + return NULL; + + for (sig = 1; sig < NSIG; sig++) { + if (sigismember(&previous, sig) != 1) + continue; + + /* Handle the case where it is a member by adding the signal to + the result list. Ignore the other cases because they mean the + signal isn't a member of the mask or the signal was invalid, + and an invalid signal must have been our fault in constructing + the loop boundaries. */ + signum = PyLong_FromLong(sig); + if (signum == NULL) { + Py_DECREF(result); + return NULL; + } + if (PyList_Append(result, signum) == -1) { + Py_DECREF(signum); + Py_DECREF(result); + return NULL; + } + Py_DECREF(signum); + } + return result; +} + +PyDoc_STRVAR(signal_pthread_sigmask_doc, +"pthread_sigmask(how, mask) -> old mask\n\ +\n\ +Fetch and/or change the signal mask of the calling thread."); +#endif /* #ifdef PYPTHREAD_SIGMASK */ + /* List of functions defined in the module */ static PyMethodDef signal_methods[] = { @@ -515,10 +627,14 @@ #endif #ifdef HAVE_PAUSE {"pause", (PyCFunction)signal_pause, - METH_NOARGS,pause_doc}, + METH_NOARGS, pause_doc}, #endif {"default_int_handler", signal_default_int_handler, METH_VARARGS, default_int_handler_doc}, +#ifdef PYPTHREAD_SIGMASK + {"pthread_sigmask", (PyCFunction)signal_pthread_sigmask, + METH_VARARGS, signal_pthread_sigmask_doc}, +#endif {NULL, NULL} /* sentinel */ }; @@ -603,6 +719,27 @@ goto finally; Py_DECREF(x); +#ifdef SIG_BLOCK + x = PyLong_FromLong(SIG_BLOCK); + if (!x || PyDict_SetItemString(d, "SIG_BLOCK", x) < 0) + goto finally; + Py_DECREF(x); +#endif + +#ifdef SIG_UNBLOCK + x = PyLong_FromLong(SIG_UNBLOCK); + if (!x || PyDict_SetItemString(d, "SIG_UNBLOCK", x) < 0) + goto finally; + Py_DECREF(x); +#endif + +#ifdef SIG_SETMASK + x = PyLong_FromLong(SIG_SETMASK); + if (!x || PyDict_SetItemString(d, "SIG_SETMASK", x) < 0) + goto finally; + Py_DECREF(x); +#endif + x = IntHandler = PyDict_GetItemString(d, "default_int_handler"); if (!x) goto finally; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 30 15:30:15 2011 From: python-checkins at python.org (georg.brandl) Date: Sat, 30 Apr 2011 15:30:15 +0200 Subject: [Python-checkins] cpython: Fix indentation. Message-ID: http://hg.python.org/cpython/rev/fd45c2452be3 changeset: 69712:fd45c2452be3 user: Georg Brandl date: Sat Apr 30 15:30:03 2011 +0200 summary: Fix indentation. files: Doc/whatsnew/3.3.rst | 4 ++-- 1 files changed, 2 insertions(+), 2 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 @@ -118,7 +118,7 @@ * The :mod:`sys` module has a new :func:`~sys.thread_info` :term:`struct sequence` holding informations about the thread implementation. -(:issue:`11223`) + (:issue:`11223`) signal ------ @@ -126,7 +126,7 @@ * The :mod:`signal` module has a new :func:`~signal.pthread_sigmask` function to fetch and/or change the signal mask of the calling thread. -(Contributed by Jean-Paul Calderone in :issue:`8407`) + (Contributed by Jean-Paul Calderone in :issue:`8407`) Optimizations -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 30 20:14:11 2011 From: python-checkins at python.org (benjamin.peterson) Date: Sat, 30 Apr 2011 20:14:11 +0200 Subject: [Python-checkins] cpython (3.1): fix function name in example (closes #11966) Message-ID: http://hg.python.org/cpython/rev/b3e7ffe6d727 changeset: 69713:b3e7ffe6d727 branch: 3.1 parent: 69699:cd68b3031f00 user: Benjamin Peterson date: Sat Apr 30 13:14:56 2011 -0500 summary: fix function name in example (closes #11966) files: Doc/c-api/module.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/c-api/module.rst b/Doc/c-api/module.rst --- a/Doc/c-api/module.rst +++ b/Doc/c-api/module.rst @@ -192,7 +192,7 @@ .. cfunction:: int PyModule_AddIntMacro(PyObject *module, macro) Add an int constant to *module*. The name and the value are taken from - *macro*. For example ``PyModule_AddConstant(module, AF_INET)`` adds the int + *macro*. For example ``PyModule_AddIntMacro(module, AF_INET)`` adds the int constant *AF_INET* with the value of *AF_INET* to *module*. Return ``-1`` on error, ``0`` on success. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 30 20:14:12 2011 From: python-checkins at python.org (benjamin.peterson) Date: Sat, 30 Apr 2011 20:14:12 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): merge 3.1 Message-ID: http://hg.python.org/cpython/rev/6e9aedf6ef24 changeset: 69714:6e9aedf6ef24 branch: 3.2 parent: 69708:2caf82aee7a4 parent: 69713:b3e7ffe6d727 user: Benjamin Peterson date: Sat Apr 30 13:15:18 2011 -0500 summary: merge 3.1 files: Doc/c-api/module.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/c-api/module.rst b/Doc/c-api/module.rst --- a/Doc/c-api/module.rst +++ b/Doc/c-api/module.rst @@ -205,7 +205,7 @@ .. c:function:: int PyModule_AddIntMacro(PyObject *module, macro) Add an int constant to *module*. The name and the value are taken from - *macro*. For example ``PyModule_AddConstant(module, AF_INET)`` adds the int + *macro*. For example ``PyModule_AddIntMacro(module, AF_INET)`` adds the int constant *AF_INET* with the value of *AF_INET* to *module*. Return ``-1`` on error, ``0`` on success. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 30 20:14:14 2011 From: python-checkins at python.org (benjamin.peterson) Date: Sat, 30 Apr 2011 20:14:14 +0200 Subject: [Python-checkins] cpython (2.7): fix function name in example (closes #11966) Message-ID: http://hg.python.org/cpython/rev/fb709d9fe92a changeset: 69715:fb709d9fe92a branch: 2.7 parent: 69704:1a45c92f9716 user: Benjamin Peterson date: Sat Apr 30 13:14:56 2011 -0500 summary: fix function name in example (closes #11966) files: Doc/c-api/module.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/c-api/module.rst b/Doc/c-api/module.rst --- a/Doc/c-api/module.rst +++ b/Doc/c-api/module.rst @@ -107,7 +107,7 @@ .. cfunction:: int PyModule_AddIntMacro(PyObject *module, macro) Add an int constant to *module*. The name and the value are taken from - *macro*. For example ``PyModule_AddConstant(module, AF_INET)`` adds the int + *macro*. For example ``PyModule_AddIntMacro(module, AF_INET)`` adds the int constant *AF_INET* with the value of *AF_INET* to *module*. Return ``-1`` on error, ``0`` on success. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 30 20:14:20 2011 From: python-checkins at python.org (benjamin.peterson) Date: Sat, 30 Apr 2011 20:14:20 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): merge 3.2 Message-ID: http://hg.python.org/cpython/rev/7247d9f2fce9 changeset: 69716:7247d9f2fce9 parent: 69712:fd45c2452be3 parent: 69714:6e9aedf6ef24 user: Benjamin Peterson date: Sat Apr 30 13:16:14 2011 -0500 summary: merge 3.2 files: Doc/c-api/module.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/c-api/module.rst b/Doc/c-api/module.rst --- a/Doc/c-api/module.rst +++ b/Doc/c-api/module.rst @@ -221,7 +221,7 @@ .. c:function:: int PyModule_AddIntMacro(PyObject *module, macro) Add an int constant to *module*. The name and the value are taken from - *macro*. For example ``PyModule_AddConstant(module, AF_INET)`` adds the int + *macro*. For example ``PyModule_AddIntMacro(module, AF_INET)`` adds the int constant *AF_INET* with the value of *AF_INET* to *module*. Return ``-1`` on error, ``0`` on success. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 30 22:36:51 2011 From: python-checkins at python.org (r.david.murray) Date: Sat, 30 Apr 2011 22:36:51 +0200 Subject: [Python-checkins] cpython (2.7): #11901: post-commit review fixes per Georg Brandl Message-ID: http://hg.python.org/cpython/rev/34d2fb56de9a changeset: 69717:34d2fb56de9a branch: 2.7 parent: 69715:fb709d9fe92a user: R David Murray date: Sat Apr 30 16:34:35 2011 -0400 summary: #11901: post-commit review fixes per Georg Brandl files: Doc/library/sys.rst | 14 +++++++------- 1 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -562,10 +562,10 @@ ``version_info`` value may be used for a more human-friendly encoding of the same information. - The ``hexversion`` is a 32-bit number with the following layout + The ``hexversion`` is a 32-bit number with the following layout: +-------------------------+------------------------------------------------+ - | bits (big endian order) | meaning | + | Bits (big endian order) | Meaning | +=========================+================================================+ | :const:`1-8` | ``PY_MAJOR_VERSION`` (the ``2`` in | | | ``2.1.0a3``) | @@ -577,14 +577,14 @@ | | ``2.1.0a3``) | +-------------------------+------------------------------------------------+ | :const:`25-28` | ``PY_RELEASE_LEVEL`` (``0xA`` for alpha, | - | | ``0xB`` for beta, ``0xC`` for gamma and | - | | ``0xF`` for final) | + | | ``0xB`` for beta, ``0xC`` for release | + | | candidate and ``0xF`` for final) | +-------------------------+------------------------------------------------+ | :const:`29-32` | ``PY_RELEASE_SERIAL`` (the ``3`` in | - | | ``2.1.0a3``) | + | | ``2.1.0a3``, zero for final releases) | +-------------------------+------------------------------------------------+ - thus ``2.1.0a3`` is hexversion ``0x020100a3`` + Thus ``2.1.0a3`` is hexversion ``0x020100a3``. .. versionadded:: 1.5.2 @@ -595,7 +595,7 @@ internal representation of integers. The attributes are read only. +-------------------------+----------------------------------------------+ - | attribute | explanation | + | Attribute | Explanation | +=========================+==============================================+ | :const:`bits_per_digit` | number of bits held in each digit. Python | | | integers are stored internally in base | -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 30 22:36:53 2011 From: python-checkins at python.org (r.david.murray) Date: Sat, 30 Apr 2011 22:36:53 +0200 Subject: [Python-checkins] cpython (3.1): #11901: post-commit review fixes per Georg Brandl Message-ID: http://hg.python.org/cpython/rev/2ddb4d6f826a changeset: 69718:2ddb4d6f826a branch: 3.1 parent: 69713:b3e7ffe6d727 user: R David Murray date: Sat Apr 30 16:35:29 2011 -0400 summary: #11901: post-commit review fixes per Georg Brandl files: Doc/library/sys.rst | 14 +++++++------- 1 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -450,10 +450,10 @@ struct sequence :data:`sys.version_info` may be used for a more human-friendly encoding of the same information. - The ``hexversion`` is a 32-bit number with the following layout + The ``hexversion`` is a 32-bit number with the following layout: +-------------------------+------------------------------------------------+ - | bits (big endian order) | meaning | + | Bits (big endian order) | Meaning | +=========================+================================================+ | :const:`1-8` | ``PY_MAJOR_VERSION`` (the ``2`` in | | | ``2.1.0a3``) | @@ -465,14 +465,14 @@ | | ``2.1.0a3``) | +-------------------------+------------------------------------------------+ | :const:`25-28` | ``PY_RELEASE_LEVEL`` (``0xA`` for alpha, | - | | ``0xB`` for beta, ``0xC`` for gamma and | - | | ``0xF`` for final) | + | | ``0xB`` for beta, ``0xC`` for release | + | | candidate and ``0xF`` for final) | +-------------------------+------------------------------------------------+ | :const:`29-32` | ``PY_RELEASE_SERIAL`` (the ``3`` in | - | | ``2.1.0a3``) | + | | ``2.1.0a3``, zero for final releases) | +-------------------------+------------------------------------------------+ - thus ``2.1.0a3`` is hexversion ``0x020100a3`` + Thus ``2.1.0a3`` is hexversion ``0x020100a3``. .. data:: int_info @@ -480,7 +480,7 @@ internal representation of integers. The attributes are read only. +-------------------------+----------------------------------------------+ - | attribute | explanation | + | Attribute | Explanation | +=========================+==============================================+ | :const:`bits_per_digit` | number of bits held in each digit. Python | | | integers are stored internally in base | -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 30 22:36:53 2011 From: python-checkins at python.org (r.david.murray) Date: Sat, 30 Apr 2011 22:36:53 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): Merge #11901: post-commit review fixes per Georg Brandl Message-ID: http://hg.python.org/cpython/rev/591a09cf9e62 changeset: 69719:591a09cf9e62 branch: 3.2 parent: 69714:6e9aedf6ef24 parent: 69718:2ddb4d6f826a user: R David Murray date: Sat Apr 30 16:36:08 2011 -0400 summary: Merge #11901: post-commit review fixes per Georg Brandl files: Doc/library/sys.rst | 14 +++++++------- 1 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -552,10 +552,10 @@ struct sequence :data:`sys.version_info` may be used for a more human-friendly encoding of the same information. - The ``hexversion`` is a 32-bit number with the following layout + The ``hexversion`` is a 32-bit number with the following layout: +-------------------------+------------------------------------------------+ - | bits (big endian order) | meaning | + | Bits (big endian order) | Meaning | +=========================+================================================+ | :const:`1-8` | ``PY_MAJOR_VERSION`` (the ``2`` in | | | ``2.1.0a3``) | @@ -567,14 +567,14 @@ | | ``2.1.0a3``) | +-------------------------+------------------------------------------------+ | :const:`25-28` | ``PY_RELEASE_LEVEL`` (``0xA`` for alpha, | - | | ``0xB`` for beta, ``0xC`` for gamma and | - | | ``0xF`` for final) | + | | ``0xB`` for beta, ``0xC`` for release | + | | candidate and ``0xF`` for final) | +-------------------------+------------------------------------------------+ | :const:`29-32` | ``PY_RELEASE_SERIAL`` (the ``3`` in | - | | ``2.1.0a3``) | + | | ``2.1.0a3``, zero for final releases) | +-------------------------+------------------------------------------------+ - thus ``2.1.0a3`` is hexversion ``0x020100a3`` + Thus ``2.1.0a3`` is hexversion ``0x020100a3``. .. data:: int_info @@ -582,7 +582,7 @@ internal representation of integers. The attributes are read only. +-------------------------+----------------------------------------------+ - | attribute | explanation | + | Attribute | Explanation | +=========================+==============================================+ | :const:`bits_per_digit` | number of bits held in each digit. Python | | | integers are stored internally in base | -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 30 22:36:55 2011 From: python-checkins at python.org (r.david.murray) Date: Sat, 30 Apr 2011 22:36:55 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge #11901: post-commit review fixes per Georg Brandl Message-ID: http://hg.python.org/cpython/rev/ca8e2fe68ecb changeset: 69720:ca8e2fe68ecb parent: 69716:7247d9f2fce9 parent: 69719:591a09cf9e62 user: R David Murray date: Sat Apr 30 16:36:37 2011 -0400 summary: Merge #11901: post-commit review fixes per Georg Brandl files: Doc/library/sys.rst | 14 +++++++------- 1 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -543,10 +543,10 @@ :term:`struct sequence` :data:`sys.version_info` may be used for a more human-friendly encoding of the same information. - The ``hexversion`` is a 32-bit number with the following layout + The ``hexversion`` is a 32-bit number with the following layout: +-------------------------+------------------------------------------------+ - | bits (big endian order) | meaning | + | Bits (big endian order) | Meaning | +=========================+================================================+ | :const:`1-8` | ``PY_MAJOR_VERSION`` (the ``2`` in | | | ``2.1.0a3``) | @@ -558,14 +558,14 @@ | | ``2.1.0a3``) | +-------------------------+------------------------------------------------+ | :const:`25-28` | ``PY_RELEASE_LEVEL`` (``0xA`` for alpha, | - | | ``0xB`` for beta, ``0xC`` for gamma and | - | | ``0xF`` for final) | + | | ``0xB`` for beta, ``0xC`` for release | + | | candidate and ``0xF`` for final) | +-------------------------+------------------------------------------------+ | :const:`29-32` | ``PY_RELEASE_SERIAL`` (the ``3`` in | - | | ``2.1.0a3``) | + | | ``2.1.0a3``, zero for final releases) | +-------------------------+------------------------------------------------+ - thus ``2.1.0a3`` is hexversion ``0x020100a3`` + Thus ``2.1.0a3`` is hexversion ``0x020100a3``. .. data:: int_info @@ -573,7 +573,7 @@ representation of integers. The attributes are read only. +-------------------------+----------------------------------------------+ - | attribute | explanation | + | Attribute | Explanation | +=========================+==============================================+ | :const:`bits_per_digit` | number of bits held in each digit. Python | | | integers are stored internally in base | -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 30 22:52:59 2011 From: python-checkins at python.org (vinay.sajip) Date: Sat, 30 Apr 2011 22:52:59 +0200 Subject: [Python-checkins] cpython: Updated usage of boolean values. Message-ID: http://hg.python.org/cpython/rev/9078fcce6982 changeset: 69721:9078fcce6982 user: Vinay Sajip date: Sat Apr 30 21:51:51 2011 +0100 summary: Updated usage of boolean values. files: Lib/logging/__init__.py | 10 +++++----- 1 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Lib/logging/__init__.py b/Lib/logging/__init__.py --- a/Lib/logging/__init__.py +++ b/Lib/logging/__init__.py @@ -688,14 +688,14 @@ Allow filters to be just callables. """ - rv = 1 + rv = True for f in self.filters: if hasattr(f, 'filter'): result = f.filter(record) else: result = f(record) # assume callable - will raise if not if not result: - rv = 0 + rv = False break return rv @@ -1197,9 +1197,9 @@ self.name = name self.level = _checkLevel(level) self.parent = None - self.propagate = 1 + self.propagate = True self.handlers = [] - self.disabled = 0 + self.disabled = False def setLevel(self, level): """ @@ -1567,7 +1567,7 @@ """ Delegate an exception call to the underlying logger. """ - kwargs["exc_info"] = 1 + kwargs["exc_info"] = True self.log(ERROR, msg, *args, **kwargs) def critical(self, msg, *args, **kwargs): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 30 22:53:01 2011 From: python-checkins at python.org (vinay.sajip) Date: Sat, 30 Apr 2011 22:53:01 +0200 Subject: [Python-checkins] cpython: Updated usage of boolean values. Message-ID: http://hg.python.org/cpython/rev/4fad411b4707 changeset: 69722:4fad411b4707 user: Vinay Sajip date: Sat Apr 30 21:52:26 2011 +0100 summary: Updated usage of boolean values. files: Lib/logging/handlers.py | 14 +++++++------- 1 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py --- a/Lib/logging/handlers.py +++ b/Lib/logging/handlers.py @@ -388,7 +388,7 @@ """ if not os.path.exists(self.baseFilename): stat = None - changed = 1 + changed = True else: stat = os.stat(self.baseFilename) changed = (stat[ST_DEV] != self.dev) or (stat[ST_INO] != self.ino) @@ -418,15 +418,15 @@ """ Initializes the handler with a specific host address and port. - The attribute 'closeOnError' is set to 1 - which means that if - a socket error occurs, the socket is silently closed and then - reopened on the next logging call. + When the attribute *closeOnError* is set to True - if a socket error + occurs, the socket is silently closed and then reopened on the next + logging call. """ logging.Handler.__init__(self) self.host = host self.port = port self.sock = None - self.closeOnError = 0 + self.closeOnError = False self.retryTime = None # # Exponential backoff parameters. @@ -457,7 +457,7 @@ # is the first time back after a disconnect, or # we've waited long enough. if self.retryTime is None: - attempt = 1 + attempt = True else: attempt = (now >= self.retryTime) if attempt: @@ -572,7 +572,7 @@ Initializes the handler with a specific host address and port. """ SocketHandler.__init__(self, host, port) - self.closeOnError = 0 + self.closeOnError = False def makeSocket(self): """ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 30 22:53:03 2011 From: python-checkins at python.org (vinay.sajip) Date: Sat, 30 Apr 2011 22:53:03 +0200 Subject: [Python-checkins] cpython: Improved test coverage. Message-ID: http://hg.python.org/cpython/rev/2ab07776510c changeset: 69723:2ab07776510c user: Vinay Sajip date: Sat Apr 30 21:52:48 2011 +0100 summary: Improved test coverage. files: Lib/test/test_logging.py | 109 ++++++++++++++++++++++++++- 1 files changed, 105 insertions(+), 4 deletions(-) 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 @@ -25,8 +25,11 @@ import logging.handlers import logging.config +import asynchat +import asyncore import codecs import datetime +import errno import pickle import io import gc @@ -35,6 +38,7 @@ import queue import re import select +import smtpd import socket from socketserver import ThreadingTCPServer, StreamRequestHandler import struct @@ -547,9 +551,6 @@ h.close() except socket.error: # syslogd might not be available pass - h = logging.handlers.SMTPHandler('localhost', 'me', 'you', 'Log') - self.assertEqual(h.toaddrs, ['you']) - h.close() for method in ('GET', 'POST', 'PUT'): if method == 'PUT': self.assertRaises(ValueError, logging.handlers.HTTPHandler, @@ -595,6 +596,106 @@ logging.raiseExceptions = old_raise sys.stderr = old_stderr + +TEST_SMTP_PORT = 9025 + + +class TestSMTPChannel(smtpd.SMTPChannel): + def __init__(self, server, conn, addr, sockmap): + asynchat.async_chat.__init__(self, conn, sockmap) + self.smtp_server = server + self.conn = conn + self.addr = addr + self.received_lines = [] + self.smtp_state = self.COMMAND + self.seen_greeting = '' + self.mailfrom = None + self.rcpttos = [] + self.received_data = '' + self.fqdn = socket.getfqdn() + self.num_bytes = 0 + try: + self.peer = conn.getpeername() + except socket.error as err: + # a race condition may occur if the other end is closing + # before we can get the peername + self.close() + if err.args[0] != errno.ENOTCONN: + raise + return + self.push('220 %s %s' % (self.fqdn, smtpd.__version__)) + self.set_terminator(b'\r\n') + + +class TestSMTPServer(smtpd.SMTPServer): + channel_class = TestSMTPChannel + + def __init__(self, addr, handler, poll_interval, sockmap): + self._localaddr = addr + self._remoteaddr = None + self.sockmap = sockmap + asyncore.dispatcher.__init__(self, map=sockmap) + try: + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.setblocking(0) + self.set_socket(sock, map=sockmap) + # try to re-use a server port if possible + self.set_reuse_addr() + self.bind(addr) + self.listen(5) + except: + self.close() + raise + self._handler = handler + self._thread = None + self.poll_interval = poll_interval + + def handle_accepted(self, conn, addr): + print('Incoming connection from %s' % repr(addr), file=smtpd.DEBUGSTREAM) + channel = self.channel_class(self, conn, addr, self.sockmap) + + def process_message(self, peer, mailfrom, rcpttos, data): + self._handler(peer, mailfrom, rcpttos, data) + + def start(self): + self._thread = t = threading.Thread(target=self.serve_forever, + args=(self.poll_interval,)) + t.setDaemon(True) + t.start() + + def serve_forever(self, poll_interval): + asyncore.loop(poll_interval, map=self.sockmap) + + def stop(self): + self.close() + self._thread.join() + self._thread = None + + +class SMTPHandlerTest(BaseTest): + def test_basic(self): + addr = ('localhost', TEST_SMTP_PORT) + h = logging.handlers.SMTPHandler(addr, 'me', 'you', 'Log') + self.assertEqual(h.toaddrs, ['you']) + self.messages = [] + sockmap = {} + server = TestSMTPServer(addr, self.process_message, 0.001, sockmap) + server.start() + r = logging.makeLogRecord({'msg': 'Hello'}) + h.handle(r) + server.stop() + self.assertEqual(len(self.messages), 1) + peer, mailfrom, rcpttos, data = self.messages[0] + self.assertEqual(mailfrom, 'me') + self.assertEqual(rcpttos, ['you']) + self.assertTrue('\nSubject: Log\n' in data) + self.assertTrue(data.endswith('\n\nHello')) + h.close() + + def process_message(self, *args): + self.messages.append(args) + + class MemoryHandlerTest(BaseTest): """Tests for the MemoryHandler.""" @@ -3142,7 +3243,7 @@ FormatterTest, BufferingFormatterTest, StreamHandlerTest, LogRecordFactoryTest, ChildLoggerTest, QueueHandlerTest, ShutdownTest, ModuleLevelMiscTest, BasicConfigTest, - LoggerAdapterTest, LoggerTest, + LoggerAdapterTest, LoggerTest, SMTPHandlerTest, FileHandlerTest, RotatingFileHandlerTest, LastResortTest, LogRecordTest, ExceptionTest, TimedRotatingFileHandlerTest -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 30 23:03:59 2011 From: python-checkins at python.org (ezio.melotti) Date: Sat, 30 Apr 2011 23:03:59 +0200 Subject: [Python-checkins] cpython: Fix test. Message-ID: http://hg.python.org/cpython/rev/f3b4a4e06908 changeset: 69724:f3b4a4e06908 user: Ezio Melotti date: Sun May 01 00:03:49 2011 +0300 summary: Fix test. files: Lib/test/test_sys.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) 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 @@ -478,7 +478,7 @@ 'Threading required for this test.') def test_thread_info(self): info = sys.thread_info - self.assertTrue(len(info), 3) + self.assertEqual(len(info), 3) self.assertIn(info.name, ('nt', 'os2', 'pthread', 'solaris', None)) self.assertIn(info.lock, ('semaphore', 'mutex+cond', None)) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 30 23:21:03 2011 From: python-checkins at python.org (r.david.murray) Date: Sat, 30 Apr 2011 23:21:03 +0200 Subject: [Python-checkins] cpython (3.2): #11883: replace incorrect call to sendmail with correct call to send_message Message-ID: http://hg.python.org/cpython/rev/5c61c1d583fd changeset: 69725:5c61c1d583fd branch: 3.2 parent: 69719:591a09cf9e62 user: R David Murray date: Sat Apr 30 17:19:53 2011 -0400 summary: #11883: replace incorrect call to sendmail with correct call to send_message files: Doc/includes/email-simple.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/includes/email-simple.py b/Doc/includes/email-simple.py --- a/Doc/includes/email-simple.py +++ b/Doc/includes/email-simple.py @@ -19,5 +19,5 @@ # Send the message via our own SMTP server. s = smtplib.SMTP() -s.sendmail(msg) +s.send_message(msg) s.quit() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 30 23:21:06 2011 From: python-checkins at python.org (r.david.murray) Date: Sat, 30 Apr 2011 23:21:06 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge #11883: replace incorrect call to sendmail with correct call to Message-ID: http://hg.python.org/cpython/rev/fcfaeab42f6e changeset: 69726:fcfaeab42f6e parent: 69724:f3b4a4e06908 parent: 69725:5c61c1d583fd user: R David Murray date: Sat Apr 30 17:20:44 2011 -0400 summary: Merge #11883: replace incorrect call to sendmail with correct call to send_message files: Doc/includes/email-simple.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/includes/email-simple.py b/Doc/includes/email-simple.py --- a/Doc/includes/email-simple.py +++ b/Doc/includes/email-simple.py @@ -19,5 +19,5 @@ # Send the message via our own SMTP server. s = smtplib.SMTP() -s.sendmail(msg) +s.send_message(msg) s.quit() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 30 23:29:39 2011 From: python-checkins at python.org (r.david.murray) Date: Sat, 30 Apr 2011 23:29:39 +0200 Subject: [Python-checkins] cpython (2.7): #11883: fix email examples by adding 'localhost' to SMTP constructor calls Message-ID: http://hg.python.org/cpython/rev/a9cb47d0241e changeset: 69727:a9cb47d0241e branch: 2.7 parent: 69717:34d2fb56de9a user: R David Murray date: Sat Apr 30 17:26:02 2011 -0400 summary: #11883: fix email examples by adding 'localhost' to SMTP constructor calls files: Doc/includes/email-dir.py | 2 +- Doc/includes/email-mime.py | 2 +- Doc/includes/email-simple.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/includes/email-dir.py b/Doc/includes/email-dir.py --- a/Doc/includes/email-dir.py +++ b/Doc/includes/email-dir.py @@ -105,7 +105,7 @@ fp.write(composed) fp.close() else: - s = smtplib.SMTP() + s = smtplib.SMTP('localhost') s.sendmail(opts.sender, opts.recipients, composed) s.quit() diff --git a/Doc/includes/email-mime.py b/Doc/includes/email-mime.py --- a/Doc/includes/email-mime.py +++ b/Doc/includes/email-mime.py @@ -26,6 +26,6 @@ msg.attach(img) # Send the email via our own SMTP server. -s = smtplib.SMTP() +s = smtplib.SMTP('localhost') s.sendmail(me, family, msg.as_string()) s.quit() diff --git a/Doc/includes/email-simple.py b/Doc/includes/email-simple.py --- a/Doc/includes/email-simple.py +++ b/Doc/includes/email-simple.py @@ -19,6 +19,6 @@ # Send the message via our own SMTP server, but don't include the # envelope header. -s = smtplib.SMTP() +s = smtplib.SMTP('localhost') s.sendmail(me, [you], msg.as_string()) s.quit() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 30 23:29:40 2011 From: python-checkins at python.org (r.david.murray) Date: Sat, 30 Apr 2011 23:29:40 +0200 Subject: [Python-checkins] cpython (3.1): #11883: fix email examples by adding 'localhost' to SMTP constructor calls Message-ID: http://hg.python.org/cpython/rev/00ff8825f551 changeset: 69728:00ff8825f551 branch: 3.1 parent: 69718:2ddb4d6f826a user: R David Murray date: Sat Apr 30 17:26:32 2011 -0400 summary: #11883: fix email examples by adding 'localhost' to SMTP constructor calls files: Doc/includes/email-dir.py | 2 +- Doc/includes/email-mime.py | 2 +- Doc/includes/email-simple.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/includes/email-dir.py b/Doc/includes/email-dir.py --- a/Doc/includes/email-dir.py +++ b/Doc/includes/email-dir.py @@ -105,7 +105,7 @@ fp.write(composed) fp.close() else: - s = smtplib.SMTP() + s = smtplib.SMTP('localhost') s.sendmail(opts.sender, opts.recipients, composed) s.quit() diff --git a/Doc/includes/email-mime.py b/Doc/includes/email-mime.py --- a/Doc/includes/email-mime.py +++ b/Doc/includes/email-mime.py @@ -26,6 +26,6 @@ msg.attach(img) # Send the email via our own SMTP server. -s = smtplib.SMTP() +s = smtplib.SMTP('localhost') s.sendmail(me, family, msg.as_string()) s.quit() diff --git a/Doc/includes/email-simple.py b/Doc/includes/email-simple.py --- a/Doc/includes/email-simple.py +++ b/Doc/includes/email-simple.py @@ -19,6 +19,6 @@ # Send the message via our own SMTP server, but don't include the # envelope header. -s = smtplib.SMTP() +s = smtplib.SMTP('localhost') s.sendmail(me, [you], msg.as_string()) s.quit() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 30 23:29:40 2011 From: python-checkins at python.org (r.david.murray) Date: Sat, 30 Apr 2011 23:29:40 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): Merge #11883: fix email examples by adding 'localhost' to SMTP constructor calls Message-ID: http://hg.python.org/cpython/rev/0f14dd4e644e changeset: 69729:0f14dd4e644e branch: 3.2 parent: 69725:5c61c1d583fd parent: 69728:00ff8825f551 user: R David Murray date: Sat Apr 30 17:29:08 2011 -0400 summary: Merge #11883: fix email examples by adding 'localhost' to SMTP constructor calls files: Doc/includes/email-dir.py | 2 +- Doc/includes/email-mime.py | 2 +- Doc/includes/email-simple.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/includes/email-dir.py b/Doc/includes/email-dir.py --- a/Doc/includes/email-dir.py +++ b/Doc/includes/email-dir.py @@ -105,7 +105,7 @@ fp.write(composed) fp.close() else: - s = smtplib.SMTP() + s = smtplib.SMTP('localhost') s.sendmail(opts.sender, opts.recipients, composed) s.quit() diff --git a/Doc/includes/email-mime.py b/Doc/includes/email-mime.py --- a/Doc/includes/email-mime.py +++ b/Doc/includes/email-mime.py @@ -26,6 +26,6 @@ msg.attach(img) # Send the email via our own SMTP server. -s = smtplib.SMTP() +s = smtplib.SMTP('localhost') s.send_message(msg) s.quit() diff --git a/Doc/includes/email-simple.py b/Doc/includes/email-simple.py --- a/Doc/includes/email-simple.py +++ b/Doc/includes/email-simple.py @@ -18,6 +18,6 @@ msg['To'] = you # Send the message via our own SMTP server. -s = smtplib.SMTP() +s = smtplib.SMTP('localhost') s.send_message(msg) s.quit() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Apr 30 23:29:42 2011 From: python-checkins at python.org (r.david.murray) Date: Sat, 30 Apr 2011 23:29:42 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge #11883: fix email examples by adding 'localhost' to SMTP constructor calls Message-ID: http://hg.python.org/cpython/rev/cfc02e132c12 changeset: 69730:cfc02e132c12 parent: 69726:fcfaeab42f6e parent: 69729:0f14dd4e644e user: R David Murray date: Sat Apr 30 17:29:28 2011 -0400 summary: Merge #11883: fix email examples by adding 'localhost' to SMTP constructor calls files: Doc/includes/email-dir.py | 2 +- Doc/includes/email-mime.py | 2 +- Doc/includes/email-simple.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/includes/email-dir.py b/Doc/includes/email-dir.py --- a/Doc/includes/email-dir.py +++ b/Doc/includes/email-dir.py @@ -105,7 +105,7 @@ fp.write(composed) fp.close() else: - s = smtplib.SMTP() + s = smtplib.SMTP('localhost') s.sendmail(opts.sender, opts.recipients, composed) s.quit() diff --git a/Doc/includes/email-mime.py b/Doc/includes/email-mime.py --- a/Doc/includes/email-mime.py +++ b/Doc/includes/email-mime.py @@ -26,6 +26,6 @@ msg.attach(img) # Send the email via our own SMTP server. -s = smtplib.SMTP() +s = smtplib.SMTP('localhost') s.send_message(msg) s.quit() diff --git a/Doc/includes/email-simple.py b/Doc/includes/email-simple.py --- a/Doc/includes/email-simple.py +++ b/Doc/includes/email-simple.py @@ -18,6 +18,6 @@ msg['To'] = you # Send the message via our own SMTP server. -s = smtplib.SMTP() +s = smtplib.SMTP('localhost') s.send_message(msg) s.quit() -- Repository URL: http://hg.python.org/cpython